mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-25 10:43:19 -03:00
Make whitebind/whitelist permissions more flexible
This commit is contained in:
parent
e5fdda68c6
commit
e5b26deaaa
8 changed files with 321 additions and 43 deletions
|
@ -150,6 +150,7 @@ BITCOIN_CORE_H = \
|
|||
merkleblock.h \
|
||||
miner.h \
|
||||
net.h \
|
||||
net_permissions.h \
|
||||
net_processing.h \
|
||||
netaddress.h \
|
||||
netbase.h \
|
||||
|
@ -454,6 +455,7 @@ libbitcoin_common_a_SOURCES = \
|
|||
merkleblock.cpp \
|
||||
netaddress.cpp \
|
||||
netbase.cpp \
|
||||
net_permissions.cpp \
|
||||
outputtype.cpp \
|
||||
policy/feerate.cpp \
|
||||
policy/policy.cpp \
|
||||
|
|
20
src/init.cpp
20
src/init.cpp
|
@ -27,6 +27,7 @@
|
|||
#include <key.h>
|
||||
#include <miner.h>
|
||||
#include <net.h>
|
||||
#include <net_permissions.h>
|
||||
#include <net_processing.h>
|
||||
#include <netbase.h>
|
||||
#include <policy/feerate.h>
|
||||
|
@ -1775,21 +1776,16 @@ bool AppInitMain(InitInterfaces& interfaces)
|
|||
connOptions.vBinds.push_back(addrBind);
|
||||
}
|
||||
for (const std::string& strBind : gArgs.GetArgs("-whitebind")) {
|
||||
CService addrBind;
|
||||
if (!Lookup(strBind.c_str(), addrBind, 0, false)) {
|
||||
return InitError(ResolveErrMsg("whitebind", strBind));
|
||||
}
|
||||
if (addrBind.GetPort() == 0) {
|
||||
return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'").translated, strBind));
|
||||
}
|
||||
connOptions.vWhiteBinds.push_back(addrBind);
|
||||
NetWhitebindPermissions whitebind;
|
||||
std::string error;
|
||||
if (!NetWhitebindPermissions::TryParse(strBind, whitebind, error)) return InitError(error);
|
||||
connOptions.vWhiteBinds.push_back(whitebind);
|
||||
}
|
||||
|
||||
for (const auto& net : gArgs.GetArgs("-whitelist")) {
|
||||
CSubNet subnet;
|
||||
LookupSubNet(net.c_str(), subnet);
|
||||
if (!subnet.IsValid())
|
||||
return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'").translated, net));
|
||||
NetWhitelistPermissions subnet;
|
||||
std::string error;
|
||||
if (!NetWhitelistPermissions::TryParse(net, subnet, error)) return InitError(error);
|
||||
connOptions.vWhitelistedRange.push_back(subnet);
|
||||
}
|
||||
|
||||
|
|
59
src/net.cpp
59
src/net.cpp
|
@ -16,6 +16,7 @@
|
|||
#include <crypto/common.h>
|
||||
#include <crypto/sha256.h>
|
||||
#include <netbase.h>
|
||||
#include <net_permissions.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <scheduler.h>
|
||||
#include <ui_interface.h>
|
||||
|
@ -67,7 +68,6 @@ enum BindFlags {
|
|||
BF_NONE = 0,
|
||||
BF_EXPLICIT = (1U << 0),
|
||||
BF_REPORT_ERROR = (1U << 1),
|
||||
BF_WHITELIST = (1U << 2),
|
||||
};
|
||||
|
||||
// The set of sockets cannot be modified while waiting
|
||||
|
@ -459,12 +459,10 @@ void CNode::CloseSocketDisconnect()
|
|||
}
|
||||
}
|
||||
|
||||
bool CConnman::IsWhitelistedRange(const CNetAddr &addr) {
|
||||
for (const CSubNet& subnet : vWhitelistedRange) {
|
||||
if (subnet.Match(addr))
|
||||
return true;
|
||||
void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const {
|
||||
for (const auto& subnet : vWhitelistedRange) {
|
||||
if (subnet.m_subnet.Match(addr)) NetPermissions::AddFlag(flags, subnet.m_flags);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string CNode::GetAddrName() const {
|
||||
|
@ -529,6 +527,7 @@ void CNode::copyStats(CNodeStats &stats)
|
|||
X(nRecvBytes);
|
||||
}
|
||||
X(fWhitelisted);
|
||||
X(m_permissionFlags);
|
||||
{
|
||||
LOCK(cs_feeFilter);
|
||||
X(minFeeFilter);
|
||||
|
@ -904,7 +903,20 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
|
|||
}
|
||||
}
|
||||
|
||||
bool whitelisted = hListenSocket.whitelisted || IsWhitelistedRange(addr);
|
||||
NetPermissionFlags permissionFlags = NetPermissionFlags::PF_NONE;
|
||||
hListenSocket.AddSocketPermissionFlags(permissionFlags);
|
||||
AddWhitelistPermissionFlags(permissionFlags, addr);
|
||||
const bool noban = NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::PF_NOBAN);
|
||||
bool legacyWhitelisted = false;
|
||||
if (NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::PF_ISIMPLICIT)) {
|
||||
NetPermissions::ClearFlag(permissionFlags, PF_ISIMPLICIT);
|
||||
if (gArgs.GetBoolArg("-whitelistforcerelay", false)) NetPermissions::AddFlag(permissionFlags, PF_FORCERELAY);
|
||||
if (gArgs.GetBoolArg("-whitelistrelay", false)) NetPermissions::AddFlag(permissionFlags, PF_RELAY);
|
||||
NetPermissions::AddFlag(permissionFlags, PF_MEMPOOL);
|
||||
NetPermissions::AddFlag(permissionFlags, PF_NOBAN);
|
||||
legacyWhitelisted = true;
|
||||
}
|
||||
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
for (const CNode* pnode : vNodes) {
|
||||
|
@ -941,7 +953,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
|
|||
|
||||
// Don't accept connections from banned peers, but if our inbound slots aren't almost full, accept
|
||||
// if the only banning reason was an automatic misbehavior ban.
|
||||
if (!whitelisted && bannedlevel > ((nInbound + 1 < nMaxInbound) ? 1 : 0))
|
||||
if (!noban && bannedlevel > ((nInbound + 1 < nMaxInbound) ? 1 : 0))
|
||||
{
|
||||
LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToString());
|
||||
CloseSocket(hSocket);
|
||||
|
@ -962,9 +974,15 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
|
|||
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
|
||||
CAddress addr_bind = GetBindAddress(hSocket);
|
||||
|
||||
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true);
|
||||
ServiceFlags nodeServices = nLocalServices;
|
||||
if (NetPermissions::HasFlag(permissionFlags, PF_BLOOMFILTER)) {
|
||||
nodeServices = static_cast<ServiceFlags>(nodeServices | NODE_BLOOM);
|
||||
}
|
||||
CNode* pnode = new CNode(id, nodeServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true);
|
||||
pnode->AddRef();
|
||||
pnode->fWhitelisted = whitelisted;
|
||||
pnode->m_permissionFlags = permissionFlags;
|
||||
// If this flag is present, the user probably expect that RPC and QT report it as whitelisted (backward compatibility)
|
||||
pnode->fWhitelisted = legacyWhitelisted;
|
||||
pnode->m_prefer_evict = bannedlevel > 0;
|
||||
m_msgproc->InitializeNode(pnode);
|
||||
|
||||
|
@ -1983,7 +2001,7 @@ void CConnman::ThreadMessageHandler()
|
|||
|
||||
|
||||
|
||||
bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, bool fWhitelisted)
|
||||
bool CConnman::BindListenPort(const CService& addrBind, std::string& strError, NetPermissionFlags permissions)
|
||||
{
|
||||
strError = "";
|
||||
int nOne = 1;
|
||||
|
@ -2044,9 +2062,9 @@ bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, b
|
|||
return false;
|
||||
}
|
||||
|
||||
vhListenSocket.push_back(ListenSocket(hListenSocket, fWhitelisted));
|
||||
vhListenSocket.push_back(ListenSocket(hListenSocket, permissions));
|
||||
|
||||
if (addrBind.IsRoutable() && fDiscover && !fWhitelisted)
|
||||
if (addrBind.IsRoutable() && fDiscover && (permissions & PF_NOBAN) == 0)
|
||||
AddLocal(addrBind, LOCAL_BIND);
|
||||
|
||||
return true;
|
||||
|
@ -2130,11 +2148,11 @@ NodeId CConnman::GetNewNodeId()
|
|||
}
|
||||
|
||||
|
||||
bool CConnman::Bind(const CService &addr, unsigned int flags) {
|
||||
bool CConnman::Bind(const CService &addr, unsigned int flags, NetPermissionFlags permissions) {
|
||||
if (!(flags & BF_EXPLICIT) && !IsReachable(addr))
|
||||
return false;
|
||||
std::string strError;
|
||||
if (!BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) {
|
||||
if (!BindListenPort(addr, strError, permissions)) {
|
||||
if ((flags & BF_REPORT_ERROR) && clientInterface) {
|
||||
clientInterface->ThreadSafeMessageBox(strError, "", CClientUIInterface::MSG_ERROR);
|
||||
}
|
||||
|
@ -2143,20 +2161,21 @@ bool CConnman::Bind(const CService &addr, unsigned int flags) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CConnman::InitBinds(const std::vector<CService>& binds, const std::vector<CService>& whiteBinds) {
|
||||
bool CConnman::InitBinds(const std::vector<CService>& binds, const std::vector<NetWhitebindPermissions>& whiteBinds)
|
||||
{
|
||||
bool fBound = false;
|
||||
for (const auto& addrBind : binds) {
|
||||
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
|
||||
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR), NetPermissionFlags::PF_NONE);
|
||||
}
|
||||
for (const auto& addrBind : whiteBinds) {
|
||||
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
|
||||
fBound |= Bind(addrBind.m_service, (BF_EXPLICIT | BF_REPORT_ERROR), addrBind.m_flags);
|
||||
}
|
||||
if (binds.empty() && whiteBinds.empty()) {
|
||||
struct in_addr inaddr_any;
|
||||
inaddr_any.s_addr = INADDR_ANY;
|
||||
struct in6_addr inaddr6_any = IN6ADDR_ANY_INIT;
|
||||
fBound |= Bind(CService(inaddr6_any, GetListenPort()), BF_NONE);
|
||||
fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
|
||||
fBound |= Bind(CService(inaddr6_any, GetListenPort()), BF_NONE, NetPermissionFlags::PF_NONE);
|
||||
fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE, NetPermissionFlags::PF_NONE);
|
||||
}
|
||||
return fBound;
|
||||
}
|
||||
|
|
30
src/net.h
30
src/net.h
|
@ -15,6 +15,7 @@
|
|||
#include <hash.h>
|
||||
#include <limitedmap.h>
|
||||
#include <netaddress.h>
|
||||
#include <net_permissions.h>
|
||||
#include <policy/feerate.h>
|
||||
#include <protocol.h>
|
||||
#include <random.h>
|
||||
|
@ -138,8 +139,9 @@ public:
|
|||
uint64_t nMaxOutboundLimit = 0;
|
||||
int64_t m_peer_connect_timeout = DEFAULT_PEER_CONNECT_TIMEOUT;
|
||||
std::vector<std::string> vSeedNodes;
|
||||
std::vector<CSubNet> vWhitelistedRange;
|
||||
std::vector<CService> vBinds, vWhiteBinds;
|
||||
std::vector<NetWhitelistPermissions> vWhitelistedRange;
|
||||
std::vector<NetWhitebindPermissions> vWhiteBinds;
|
||||
std::vector<CService> vBinds;
|
||||
bool m_use_addrman_outgoing = true;
|
||||
std::vector<std::string> m_specified_outgoing;
|
||||
std::vector<std::string> m_added_nodes;
|
||||
|
@ -314,15 +316,17 @@ public:
|
|||
|
||||
private:
|
||||
struct ListenSocket {
|
||||
public:
|
||||
SOCKET socket;
|
||||
bool whitelisted;
|
||||
|
||||
ListenSocket(SOCKET socket_, bool whitelisted_) : socket(socket_), whitelisted(whitelisted_) {}
|
||||
inline void AddSocketPermissionFlags(NetPermissionFlags& flags) const { NetPermissions::AddFlag(flags, m_permissions); }
|
||||
ListenSocket(SOCKET socket_, NetPermissionFlags permissions_) : socket(socket_), m_permissions(permissions_) {}
|
||||
private:
|
||||
NetPermissionFlags m_permissions;
|
||||
};
|
||||
|
||||
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
|
||||
bool Bind(const CService &addr, unsigned int flags);
|
||||
bool InitBinds(const std::vector<CService>& binds, const std::vector<CService>& whiteBinds);
|
||||
bool BindListenPort(const CService& bindAddr, std::string& strError, NetPermissionFlags permissions);
|
||||
bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
|
||||
bool InitBinds(const std::vector<CService>& binds, const std::vector<NetWhitebindPermissions>& whiteBinds);
|
||||
void ThreadOpenAddedConnections();
|
||||
void AddOneShot(const std::string& strDest);
|
||||
void ProcessOneShot();
|
||||
|
@ -347,7 +351,7 @@ private:
|
|||
|
||||
bool AttemptToEvictConnection();
|
||||
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, bool manual_connection);
|
||||
bool IsWhitelistedRange(const CNetAddr &addr);
|
||||
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const;
|
||||
|
||||
void DeleteNode(CNode* pnode);
|
||||
|
||||
|
@ -380,7 +384,7 @@ private:
|
|||
|
||||
// Whitelisted ranges. Any node connecting from these is automatically
|
||||
// whitelisted (as well as those connecting to whitelisted binds).
|
||||
std::vector<CSubNet> vWhitelistedRange;
|
||||
std::vector<NetWhitelistPermissions> vWhitelistedRange;
|
||||
|
||||
unsigned int nSendBufferMaxSize{0};
|
||||
unsigned int nReceiveFloodSize{0};
|
||||
|
@ -448,7 +452,6 @@ void StartMapPort();
|
|||
void InterruptMapPort();
|
||||
void StopMapPort();
|
||||
unsigned short GetListenPort();
|
||||
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
|
||||
|
||||
struct CombinerAll
|
||||
{
|
||||
|
@ -555,6 +558,7 @@ public:
|
|||
mapMsgCmdSize mapSendBytesPerMsgCmd;
|
||||
uint64_t nRecvBytes;
|
||||
mapMsgCmdSize mapRecvBytesPerMsgCmd;
|
||||
NetPermissionFlags m_permissionFlags;
|
||||
bool fWhitelisted;
|
||||
double dPingTime;
|
||||
double dPingWait;
|
||||
|
@ -657,6 +661,9 @@ public:
|
|||
*/
|
||||
std::string cleanSubVer GUARDED_BY(cs_SubVer){};
|
||||
bool m_prefer_evict{false}; // This peer is preferred for eviction.
|
||||
bool HasPermission(NetPermissionFlags permission) const {
|
||||
return NetPermissions::HasFlag(m_permissionFlags, permission);
|
||||
}
|
||||
bool fWhitelisted{false}; // This peer can bypass DoS banning.
|
||||
bool fFeeler{false}; // If true this node is being used as a short lived feeler.
|
||||
bool fOneShot{false};
|
||||
|
@ -753,6 +760,7 @@ private:
|
|||
const ServiceFlags nLocalServices;
|
||||
const int nMyStartingHeight;
|
||||
int nSendVersion{0};
|
||||
NetPermissionFlags m_permissionFlags{ PF_NONE };
|
||||
std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread
|
||||
|
||||
mutable CCriticalSection cs_addrName;
|
||||
|
|
106
src/net_permissions.cpp
Normal file
106
src/net_permissions.cpp
Normal file
|
@ -0,0 +1,106 @@
|
|||
// Copyright (c) 2009-2018 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 <net_permissions.h>
|
||||
#include <util/system.h>
|
||||
#include <util/translation.h>
|
||||
#include <netbase.h>
|
||||
|
||||
// The parse the following format "perm1,perm2@xxxxxx"
|
||||
bool TryParsePermissionFlags(const std::string str, NetPermissionFlags& output, size_t& readen, std::string& error)
|
||||
{
|
||||
NetPermissionFlags flags = PF_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, PF_ISIMPLICIT);
|
||||
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, PF_BLOOMFILTER);
|
||||
else if (permission == "noban") NetPermissions::AddFlag(flags, PF_NOBAN);
|
||||
else if (permission == "forcerelay") NetPermissions::AddFlag(flags, PF_FORCERELAY);
|
||||
else if (permission == "mempool") NetPermissions::AddFlag(flags, PF_MEMPOOL);
|
||||
else if (permission == "all") NetPermissions::AddFlag(flags, PF_ALL);
|
||||
else if (permission == "relay") NetPermissions::AddFlag(flags, PF_RELAY);
|
||||
else if (permission.length() == 0); // Allow empty entries
|
||||
else {
|
||||
error = strprintf(_("Invalid P2P permission: '%s'").translated, permission);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
readen++;
|
||||
}
|
||||
|
||||
output = flags;
|
||||
error = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> NetPermissions::ToStrings(NetPermissionFlags flags)
|
||||
{
|
||||
std::vector<std::string> strings;
|
||||
if (NetPermissions::HasFlag(flags, PF_BLOOMFILTER)) strings.push_back("bloomfilter");
|
||||
if (NetPermissions::HasFlag(flags, PF_NOBAN)) strings.push_back("noban");
|
||||
if (NetPermissions::HasFlag(flags, PF_FORCERELAY)) strings.push_back("forcerelay");
|
||||
if (NetPermissions::HasFlag(flags, PF_RELAY)) strings.push_back("relay");
|
||||
if (NetPermissions::HasFlag(flags, PF_MEMPOOL)) strings.push_back("mempool");
|
||||
return strings;
|
||||
}
|
||||
|
||||
bool NetWhitebindPermissions::TryParse(const std::string str, NetWhitebindPermissions& output, std::string& error)
|
||||
{
|
||||
NetPermissionFlags flags;
|
||||
size_t offset;
|
||||
if (!TryParsePermissionFlags(str, flags, offset, error)) return false;
|
||||
|
||||
const std::string strBind = str.substr(offset);
|
||||
CService addrBind;
|
||||
if (!Lookup(strBind.c_str(), addrBind, 0, false)) {
|
||||
error = strprintf(_("Cannot resolve -%s address: '%s'").translated, "whitebind", strBind);
|
||||
return false;
|
||||
}
|
||||
if (addrBind.GetPort() == 0) {
|
||||
error = strprintf(_("Need to specify a port with -whitebind: '%s'").translated, strBind);
|
||||
return false;
|
||||
}
|
||||
|
||||
output.m_flags = flags;
|
||||
output.m_service = addrBind;
|
||||
error = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetWhitelistPermissions::TryParse(const std::string str, NetWhitelistPermissions& output, std::string& 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.c_str(), subnet);
|
||||
if (!subnet.IsValid()) {
|
||||
error = strprintf(_("Invalid netmask specified in -whitelist: '%s'").translated, net);
|
||||
return false;
|
||||
}
|
||||
|
||||
output.m_flags = flags;
|
||||
output.m_subnet = subnet;
|
||||
error = "";
|
||||
return true;
|
||||
}
|
62
src/net_permissions.h
Normal file
62
src/net_permissions.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) 2009-2018 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 <string>
|
||||
#include <vector>
|
||||
#include <netaddress.h>
|
||||
|
||||
#ifndef BITCOIN_NET_PERMISSIONS_H
|
||||
#define BITCOIN_NET_PERMISSIONS_H
|
||||
enum NetPermissionFlags
|
||||
{
|
||||
PF_NONE = 0,
|
||||
// Can query bloomfilter even if -peerbloomfilters is false
|
||||
PF_BLOOMFILTER = (1U << 1),
|
||||
// Relay and accept transactions from this peer, even if -blocksonly is true
|
||||
PF_RELAY = (1U << 3),
|
||||
// Always relay transactions from this peer, even if already in mempool or rejected from policy
|
||||
// Keep parameter interaction: forcerelay implies relay
|
||||
PF_FORCERELAY = (1U << 2) | PF_RELAY,
|
||||
// Can't be banned for misbehavior
|
||||
PF_NOBAN = (1U << 4),
|
||||
// Can query the mempool
|
||||
PF_MEMPOOL = (1U << 5),
|
||||
|
||||
// True if the user did not specifically set fine grained permissions
|
||||
PF_ISIMPLICIT = (1U << 31),
|
||||
PF_ALL = PF_BLOOMFILTER | PF_FORCERELAY | PF_RELAY | PF_NOBAN | PF_MEMPOOL,
|
||||
};
|
||||
class NetPermissions
|
||||
{
|
||||
public:
|
||||
NetPermissionFlags m_flags;
|
||||
static std::vector<std::string> ToStrings(NetPermissionFlags flags);
|
||||
static inline bool HasFlag(const NetPermissionFlags& flags, NetPermissionFlags f)
|
||||
{
|
||||
return (flags & f) == f;
|
||||
}
|
||||
static inline void AddFlag(NetPermissionFlags& flags, NetPermissionFlags f)
|
||||
{
|
||||
flags = static_cast<NetPermissionFlags>(flags | f);
|
||||
}
|
||||
static inline void ClearFlag(NetPermissionFlags& flags, NetPermissionFlags f)
|
||||
{
|
||||
flags = static_cast<NetPermissionFlags>(flags & ~f);
|
||||
}
|
||||
};
|
||||
class NetWhitebindPermissions : public NetPermissions
|
||||
{
|
||||
public:
|
||||
static bool TryParse(const std::string str, NetWhitebindPermissions& output, std::string& error);
|
||||
CService m_service;
|
||||
};
|
||||
|
||||
class NetWhitelistPermissions : public NetPermissions
|
||||
{
|
||||
public:
|
||||
static bool TryParse(const std::string str, NetWhitelistPermissions& output, std::string& error);
|
||||
CSubNet m_subnet;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_NET_PERMISSIONS_H
|
|
@ -9,6 +9,7 @@
|
|||
#include <core_io.h>
|
||||
#include <net.h>
|
||||
#include <net_processing.h>
|
||||
#include <net_permissions.h>
|
||||
#include <netbase.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
|
@ -178,6 +179,11 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
|
|||
obj.pushKV("inflight", heights);
|
||||
}
|
||||
obj.pushKV("whitelisted", stats.fWhitelisted);
|
||||
UniValue permissions(UniValue::VARR);
|
||||
for (const auto& permission : NetPermissions::ToStrings(stats.m_permissionFlags)) {
|
||||
permissions.push_back(permission);
|
||||
}
|
||||
obj.pushKV("permissions", permissions);
|
||||
obj.pushKV("minfeefilter", ValueFromAmount(stats.minFeeFilter));
|
||||
|
||||
UniValue sendPerMsgCmd(UniValue::VOBJ);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <netbase.h>
|
||||
#include <net_permissions.h>
|
||||
#include <test/setup_common.h>
|
||||
#include <util/strencodings.h>
|
||||
|
||||
|
@ -321,4 +322,82 @@ BOOST_AUTO_TEST_CASE(netbase_parsenetwork)
|
|||
BOOST_CHECK_EQUAL(ParseNetwork(""), NET_UNROUTABLE);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(netpermissions_test)
|
||||
{
|
||||
std::string error;
|
||||
NetWhitebindPermissions whitebindPermissions;
|
||||
NetWhitelistPermissions whitelistPermissions;
|
||||
|
||||
// Detect invalid white bind
|
||||
BOOST_CHECK(!NetWhitebindPermissions::TryParse("", whitebindPermissions, error));
|
||||
BOOST_CHECK(error.find("Cannot resolve -whitebind address") != std::string::npos);
|
||||
BOOST_CHECK(!NetWhitebindPermissions::TryParse("127.0.0.1", whitebindPermissions, error));
|
||||
BOOST_CHECK(error.find("Need to specify a port with -whitebind") != std::string::npos);
|
||||
BOOST_CHECK(!NetWhitebindPermissions::TryParse("", whitebindPermissions, error));
|
||||
|
||||
// If no permission flags, assume backward compatibility
|
||||
BOOST_CHECK(NetWhitebindPermissions::TryParse("1.2.3.4:32", whitebindPermissions, error));
|
||||
BOOST_CHECK(error.empty());
|
||||
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_ISIMPLICIT);
|
||||
BOOST_CHECK(NetPermissions::HasFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT));
|
||||
NetPermissions::ClearFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT);
|
||||
BOOST_CHECK(!NetPermissions::HasFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT));
|
||||
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_NONE);
|
||||
NetPermissions::AddFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT);
|
||||
BOOST_CHECK(NetPermissions::HasFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT));
|
||||
|
||||
// Can set one permission
|
||||
BOOST_CHECK(NetWhitebindPermissions::TryParse("bloom@1.2.3.4:32", whitebindPermissions, error));
|
||||
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_BLOOMFILTER);
|
||||
BOOST_CHECK(NetWhitebindPermissions::TryParse("@1.2.3.4:32", whitebindPermissions, error));
|
||||
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_NONE);
|
||||
|
||||
// Happy path, can parse flags
|
||||
BOOST_CHECK(NetWhitebindPermissions::TryParse("bloom,forcerelay@1.2.3.4:32", whitebindPermissions, error));
|
||||
// forcerelay should also activate the relay permission
|
||||
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_BLOOMFILTER | PF_FORCERELAY | PF_RELAY);
|
||||
BOOST_CHECK(NetWhitebindPermissions::TryParse("bloom,relay,noban@1.2.3.4:32", whitebindPermissions, error));
|
||||
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_BLOOMFILTER | PF_RELAY | PF_NOBAN);
|
||||
BOOST_CHECK(NetWhitebindPermissions::TryParse("bloom,forcerelay,noban@1.2.3.4:32", whitebindPermissions, error));
|
||||
BOOST_CHECK(NetWhitebindPermissions::TryParse("all@1.2.3.4:32", whitebindPermissions, error));
|
||||
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_ALL);
|
||||
|
||||
// Allow dups
|
||||
BOOST_CHECK(NetWhitebindPermissions::TryParse("bloom,relay,noban,noban@1.2.3.4:32", whitebindPermissions, error));
|
||||
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_BLOOMFILTER | PF_RELAY | PF_NOBAN);
|
||||
|
||||
// Allow empty
|
||||
BOOST_CHECK(NetWhitebindPermissions::TryParse("bloom,relay,,noban@1.2.3.4:32", whitebindPermissions, error));
|
||||
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_BLOOMFILTER | PF_RELAY | PF_NOBAN);
|
||||
BOOST_CHECK(NetWhitebindPermissions::TryParse(",@1.2.3.4:32", whitebindPermissions, error));
|
||||
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_NONE);
|
||||
BOOST_CHECK(NetWhitebindPermissions::TryParse(",,@1.2.3.4:32", whitebindPermissions, error));
|
||||
BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_NONE);
|
||||
|
||||
// Detect invalid flag
|
||||
BOOST_CHECK(!NetWhitebindPermissions::TryParse("bloom,forcerelay,oopsie@1.2.3.4:32", whitebindPermissions, error));
|
||||
BOOST_CHECK(error.find("Invalid P2P permission") != std::string::npos);
|
||||
|
||||
// Check whitelist error
|
||||
BOOST_CHECK(!NetWhitelistPermissions::TryParse("bloom,forcerelay,noban@1.2.3.4:32", whitelistPermissions, error));
|
||||
BOOST_CHECK(error.find("Invalid netmask specified in -whitelist") != std::string::npos);
|
||||
|
||||
// Happy path for whitelist parsing
|
||||
BOOST_CHECK(NetWhitelistPermissions::TryParse("noban@1.2.3.4", whitelistPermissions, error));
|
||||
BOOST_CHECK_EQUAL(whitelistPermissions.m_flags, PF_NOBAN);
|
||||
BOOST_CHECK(NetWhitelistPermissions::TryParse("bloom,forcerelay,noban,relay@1.2.3.4/32", whitelistPermissions, error));
|
||||
BOOST_CHECK_EQUAL(whitelistPermissions.m_flags, PF_BLOOMFILTER | PF_FORCERELAY | PF_NOBAN | PF_RELAY);
|
||||
BOOST_CHECK(error.empty());
|
||||
BOOST_CHECK_EQUAL(whitelistPermissions.m_subnet.ToString(), "1.2.3.4/32");
|
||||
BOOST_CHECK(NetWhitelistPermissions::TryParse("bloom,forcerelay,noban,relay,mempool@1.2.3.4/32", whitelistPermissions, error));
|
||||
|
||||
const auto strings = NetPermissions::ToStrings(PF_ALL);
|
||||
BOOST_CHECK_EQUAL(strings.size(), 5);
|
||||
BOOST_CHECK(std::find(strings.begin(), strings.end(), "bloomfilter") != strings.end());
|
||||
BOOST_CHECK(std::find(strings.begin(), strings.end(), "forcerelay") != strings.end());
|
||||
BOOST_CHECK(std::find(strings.begin(), strings.end(), "relay") != strings.end());
|
||||
BOOST_CHECK(std::find(strings.begin(), strings.end(), "noban") != strings.end());
|
||||
BOOST_CHECK(std::find(strings.begin(), strings.end(), "mempool") != strings.end());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
Loading…
Add table
Reference in a new issue