Skip to content

Commit e5b26de

Browse files
committed
Make whitebind/whitelist permissions more flexible
1 parent e5fdda6 commit e5b26de

File tree

8 files changed

+321
-43
lines changed

8 files changed

+321
-43
lines changed

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ BITCOIN_CORE_H = \
150150
merkleblock.h \
151151
miner.h \
152152
net.h \
153+
net_permissions.h \
153154
net_processing.h \
154155
netaddress.h \
155156
netbase.h \
@@ -454,6 +455,7 @@ libbitcoin_common_a_SOURCES = \
454455
merkleblock.cpp \
455456
netaddress.cpp \
456457
netbase.cpp \
458+
net_permissions.cpp \
457459
outputtype.cpp \
458460
policy/feerate.cpp \
459461
policy/policy.cpp \

src/init.cpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <key.h>
2828
#include <miner.h>
2929
#include <net.h>
30+
#include <net_permissions.h>
3031
#include <net_processing.h>
3132
#include <netbase.h>
3233
#include <policy/feerate.h>
@@ -1775,21 +1776,16 @@ bool AppInitMain(InitInterfaces& interfaces)
17751776
connOptions.vBinds.push_back(addrBind);
17761777
}
17771778
for (const std::string& strBind : gArgs.GetArgs("-whitebind")) {
1778-
CService addrBind;
1779-
if (!Lookup(strBind.c_str(), addrBind, 0, false)) {
1780-
return InitError(ResolveErrMsg("whitebind", strBind));
1781-
}
1782-
if (addrBind.GetPort() == 0) {
1783-
return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'").translated, strBind));
1784-
}
1785-
connOptions.vWhiteBinds.push_back(addrBind);
1779+
NetWhitebindPermissions whitebind;
1780+
std::string error;
1781+
if (!NetWhitebindPermissions::TryParse(strBind, whitebind, error)) return InitError(error);
1782+
connOptions.vWhiteBinds.push_back(whitebind);
17861783
}
17871784

17881785
for (const auto& net : gArgs.GetArgs("-whitelist")) {
1789-
CSubNet subnet;
1790-
LookupSubNet(net.c_str(), subnet);
1791-
if (!subnet.IsValid())
1792-
return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'").translated, net));
1786+
NetWhitelistPermissions subnet;
1787+
std::string error;
1788+
if (!NetWhitelistPermissions::TryParse(net, subnet, error)) return InitError(error);
17931789
connOptions.vWhitelistedRange.push_back(subnet);
17941790
}
17951791

src/net.cpp

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <crypto/common.h>
1717
#include <crypto/sha256.h>
1818
#include <netbase.h>
19+
#include <net_permissions.h>
1920
#include <primitives/transaction.h>
2021
#include <scheduler.h>
2122
#include <ui_interface.h>
@@ -67,7 +68,6 @@ enum BindFlags {
6768
BF_NONE = 0,
6869
BF_EXPLICIT = (1U << 0),
6970
BF_REPORT_ERROR = (1U << 1),
70-
BF_WHITELIST = (1U << 2),
7171
};
7272

7373
// The set of sockets cannot be modified while waiting
@@ -459,12 +459,10 @@ void CNode::CloseSocketDisconnect()
459459
}
460460
}
461461

462-
bool CConnman::IsWhitelistedRange(const CNetAddr &addr) {
463-
for (const CSubNet& subnet : vWhitelistedRange) {
464-
if (subnet.Match(addr))
465-
return true;
462+
void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const {
463+
for (const auto& subnet : vWhitelistedRange) {
464+
if (subnet.m_subnet.Match(addr)) NetPermissions::AddFlag(flags, subnet.m_flags);
466465
}
467-
return false;
468466
}
469467

470468
std::string CNode::GetAddrName() const {
@@ -529,6 +527,7 @@ void CNode::copyStats(CNodeStats &stats)
529527
X(nRecvBytes);
530528
}
531529
X(fWhitelisted);
530+
X(m_permissionFlags);
532531
{
533532
LOCK(cs_feeFilter);
534533
X(minFeeFilter);
@@ -904,7 +903,20 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
904903
}
905904
}
906905

907-
bool whitelisted = hListenSocket.whitelisted || IsWhitelistedRange(addr);
906+
NetPermissionFlags permissionFlags = NetPermissionFlags::PF_NONE;
907+
hListenSocket.AddSocketPermissionFlags(permissionFlags);
908+
AddWhitelistPermissionFlags(permissionFlags, addr);
909+
const bool noban = NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::PF_NOBAN);
910+
bool legacyWhitelisted = false;
911+
if (NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::PF_ISIMPLICIT)) {
912+
NetPermissions::ClearFlag(permissionFlags, PF_ISIMPLICIT);
913+
if (gArgs.GetBoolArg("-whitelistforcerelay", false)) NetPermissions::AddFlag(permissionFlags, PF_FORCERELAY);
914+
if (gArgs.GetBoolArg("-whitelistrelay", false)) NetPermissions::AddFlag(permissionFlags, PF_RELAY);
915+
NetPermissions::AddFlag(permissionFlags, PF_MEMPOOL);
916+
NetPermissions::AddFlag(permissionFlags, PF_NOBAN);
917+
legacyWhitelisted = true;
918+
}
919+
908920
{
909921
LOCK(cs_vNodes);
910922
for (const CNode* pnode : vNodes) {
@@ -941,7 +953,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
941953

942954
// Don't accept connections from banned peers, but if our inbound slots aren't almost full, accept
943955
// if the only banning reason was an automatic misbehavior ban.
944-
if (!whitelisted && bannedlevel > ((nInbound + 1 < nMaxInbound) ? 1 : 0))
956+
if (!noban && bannedlevel > ((nInbound + 1 < nMaxInbound) ? 1 : 0))
945957
{
946958
LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToString());
947959
CloseSocket(hSocket);
@@ -962,9 +974,15 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
962974
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
963975
CAddress addr_bind = GetBindAddress(hSocket);
964976

965-
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true);
977+
ServiceFlags nodeServices = nLocalServices;
978+
if (NetPermissions::HasFlag(permissionFlags, PF_BLOOMFILTER)) {
979+
nodeServices = static_cast<ServiceFlags>(nodeServices | NODE_BLOOM);
980+
}
981+
CNode* pnode = new CNode(id, nodeServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true);
966982
pnode->AddRef();
967-
pnode->fWhitelisted = whitelisted;
983+
pnode->m_permissionFlags = permissionFlags;
984+
// If this flag is present, the user probably expect that RPC and QT report it as whitelisted (backward compatibility)
985+
pnode->fWhitelisted = legacyWhitelisted;
968986
pnode->m_prefer_evict = bannedlevel > 0;
969987
m_msgproc->InitializeNode(pnode);
970988

@@ -1983,7 +2001,7 @@ void CConnman::ThreadMessageHandler()
19832001

19842002

19852003

1986-
bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, bool fWhitelisted)
2004+
bool CConnman::BindListenPort(const CService& addrBind, std::string& strError, NetPermissionFlags permissions)
19872005
{
19882006
strError = "";
19892007
int nOne = 1;
@@ -2044,9 +2062,9 @@ bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, b
20442062
return false;
20452063
}
20462064

2047-
vhListenSocket.push_back(ListenSocket(hListenSocket, fWhitelisted));
2065+
vhListenSocket.push_back(ListenSocket(hListenSocket, permissions));
20482066

2049-
if (addrBind.IsRoutable() && fDiscover && !fWhitelisted)
2067+
if (addrBind.IsRoutable() && fDiscover && (permissions & PF_NOBAN) == 0)
20502068
AddLocal(addrBind, LOCAL_BIND);
20512069

20522070
return true;
@@ -2130,11 +2148,11 @@ NodeId CConnman::GetNewNodeId()
21302148
}
21312149

21322150

2133-
bool CConnman::Bind(const CService &addr, unsigned int flags) {
2151+
bool CConnman::Bind(const CService &addr, unsigned int flags, NetPermissionFlags permissions) {
21342152
if (!(flags & BF_EXPLICIT) && !IsReachable(addr))
21352153
return false;
21362154
std::string strError;
2137-
if (!BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) {
2155+
if (!BindListenPort(addr, strError, permissions)) {
21382156
if ((flags & BF_REPORT_ERROR) && clientInterface) {
21392157
clientInterface->ThreadSafeMessageBox(strError, "", CClientUIInterface::MSG_ERROR);
21402158
}
@@ -2143,20 +2161,21 @@ bool CConnman::Bind(const CService &addr, unsigned int flags) {
21432161
return true;
21442162
}
21452163

2146-
bool CConnman::InitBinds(const std::vector<CService>& binds, const std::vector<CService>& whiteBinds) {
2164+
bool CConnman::InitBinds(const std::vector<CService>& binds, const std::vector<NetWhitebindPermissions>& whiteBinds)
2165+
{
21472166
bool fBound = false;
21482167
for (const auto& addrBind : binds) {
2149-
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
2168+
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR), NetPermissionFlags::PF_NONE);
21502169
}
21512170
for (const auto& addrBind : whiteBinds) {
2152-
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
2171+
fBound |= Bind(addrBind.m_service, (BF_EXPLICIT | BF_REPORT_ERROR), addrBind.m_flags);
21532172
}
21542173
if (binds.empty() && whiteBinds.empty()) {
21552174
struct in_addr inaddr_any;
21562175
inaddr_any.s_addr = INADDR_ANY;
21572176
struct in6_addr inaddr6_any = IN6ADDR_ANY_INIT;
2158-
fBound |= Bind(CService(inaddr6_any, GetListenPort()), BF_NONE);
2159-
fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
2177+
fBound |= Bind(CService(inaddr6_any, GetListenPort()), BF_NONE, NetPermissionFlags::PF_NONE);
2178+
fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE, NetPermissionFlags::PF_NONE);
21602179
}
21612180
return fBound;
21622181
}

src/net.h

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <hash.h>
1616
#include <limitedmap.h>
1717
#include <netaddress.h>
18+
#include <net_permissions.h>
1819
#include <policy/feerate.h>
1920
#include <protocol.h>
2021
#include <random.h>
@@ -138,8 +139,9 @@ class CConnman
138139
uint64_t nMaxOutboundLimit = 0;
139140
int64_t m_peer_connect_timeout = DEFAULT_PEER_CONNECT_TIMEOUT;
140141
std::vector<std::string> vSeedNodes;
141-
std::vector<CSubNet> vWhitelistedRange;
142-
std::vector<CService> vBinds, vWhiteBinds;
142+
std::vector<NetWhitelistPermissions> vWhitelistedRange;
143+
std::vector<NetWhitebindPermissions> vWhiteBinds;
144+
std::vector<CService> vBinds;
143145
bool m_use_addrman_outgoing = true;
144146
std::vector<std::string> m_specified_outgoing;
145147
std::vector<std::string> m_added_nodes;
@@ -314,15 +316,17 @@ class CConnman
314316

315317
private:
316318
struct ListenSocket {
319+
public:
317320
SOCKET socket;
318-
bool whitelisted;
319-
320-
ListenSocket(SOCKET socket_, bool whitelisted_) : socket(socket_), whitelisted(whitelisted_) {}
321+
inline void AddSocketPermissionFlags(NetPermissionFlags& flags) const { NetPermissions::AddFlag(flags, m_permissions); }
322+
ListenSocket(SOCKET socket_, NetPermissionFlags permissions_) : socket(socket_), m_permissions(permissions_) {}
323+
private:
324+
NetPermissionFlags m_permissions;
321325
};
322326

323-
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
324-
bool Bind(const CService &addr, unsigned int flags);
325-
bool InitBinds(const std::vector<CService>& binds, const std::vector<CService>& whiteBinds);
327+
bool BindListenPort(const CService& bindAddr, std::string& strError, NetPermissionFlags permissions);
328+
bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
329+
bool InitBinds(const std::vector<CService>& binds, const std::vector<NetWhitebindPermissions>& whiteBinds);
326330
void ThreadOpenAddedConnections();
327331
void AddOneShot(const std::string& strDest);
328332
void ProcessOneShot();
@@ -347,7 +351,7 @@ class CConnman
347351

348352
bool AttemptToEvictConnection();
349353
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, bool manual_connection);
350-
bool IsWhitelistedRange(const CNetAddr &addr);
354+
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const;
351355

352356
void DeleteNode(CNode* pnode);
353357

@@ -380,7 +384,7 @@ class CConnman
380384

381385
// Whitelisted ranges. Any node connecting from these is automatically
382386
// whitelisted (as well as those connecting to whitelisted binds).
383-
std::vector<CSubNet> vWhitelistedRange;
387+
std::vector<NetWhitelistPermissions> vWhitelistedRange;
384388

385389
unsigned int nSendBufferMaxSize{0};
386390
unsigned int nReceiveFloodSize{0};
@@ -448,7 +452,6 @@ void StartMapPort();
448452
void InterruptMapPort();
449453
void StopMapPort();
450454
unsigned short GetListenPort();
451-
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
452455

453456
struct CombinerAll
454457
{
@@ -555,6 +558,7 @@ class CNodeStats
555558
mapMsgCmdSize mapSendBytesPerMsgCmd;
556559
uint64_t nRecvBytes;
557560
mapMsgCmdSize mapRecvBytesPerMsgCmd;
561+
NetPermissionFlags m_permissionFlags;
558562
bool fWhitelisted;
559563
double dPingTime;
560564
double dPingWait;
@@ -657,6 +661,9 @@ class CNode
657661
*/
658662
std::string cleanSubVer GUARDED_BY(cs_SubVer){};
659663
bool m_prefer_evict{false}; // This peer is preferred for eviction.
664+
bool HasPermission(NetPermissionFlags permission) const {
665+
return NetPermissions::HasFlag(m_permissionFlags, permission);
666+
}
660667
bool fWhitelisted{false}; // This peer can bypass DoS banning.
661668
bool fFeeler{false}; // If true this node is being used as a short lived feeler.
662669
bool fOneShot{false};
@@ -753,6 +760,7 @@ class CNode
753760
const ServiceFlags nLocalServices;
754761
const int nMyStartingHeight;
755762
int nSendVersion{0};
763+
NetPermissionFlags m_permissionFlags{ PF_NONE };
756764
std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread
757765

758766
mutable CCriticalSection cs_addrName;

0 commit comments

Comments
 (0)