diff --git a/src/interfaces/node.h b/src/interfaces/node.h --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -112,7 +112,10 @@ //! Unban node. virtual bool unban(const CSubNet &ip) = 0; - //! Disconnect node. + //! Disconnect node by address. + virtual bool disconnect(const CNetAddr &net_addr) = 0; + + //! Disconnect node by id. virtual bool disconnect(NodeId id) = 0; //! Get total bytes recv. diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -152,6 +152,12 @@ } return false; } + bool disconnect(const CNetAddr &net_addr) override { + if (g_connman) { + return g_connman->DisconnectNode(net_addr); + } + return false; + } bool disconnect(NodeId id) override { if (g_connman) { return g_connman->DisconnectNode(id); diff --git a/src/net.h b/src/net.h --- a/src/net.h +++ b/src/net.h @@ -282,6 +282,8 @@ size_t GetNodeCount(NumConnections num); void GetNodeStats(std::vector &vstats); bool DisconnectNode(const std::string &node); + bool DisconnectNode(const CSubNet &subnet); + bool DisconnectNode(const CNetAddr &addr); bool DisconnectNode(NodeId id); ServiceFlags GetLocalServices() const; diff --git a/src/net.cpp b/src/net.cpp --- a/src/net.cpp +++ b/src/net.cpp @@ -575,15 +575,6 @@ clientInterface->BannedListChanged(); } - { - LOCK(cs_vNodes); - for (CNode *pnode : vNodes) { - if (subNet.Match(static_cast(pnode->addr))) { - pnode->fDisconnect = true; - } - } - } - if (banReason == BanReasonManuallyAdded) { // Store banlist to disk immediately if user requested ban. DumpBanlist(); @@ -2733,6 +2724,23 @@ } return false; } + +bool CConnman::DisconnectNode(const CSubNet &subnet) { + bool disconnected = false; + LOCK(cs_vNodes); + for (CNode *pnode : vNodes) { + if (subnet.Match(pnode->addr)) { + pnode->fDisconnect = true; + disconnected = true; + } + } + return disconnected; +} + +bool CConnman::DisconnectNode(const CNetAddr &addr) { + return DisconnectNode(CSubNet(addr)); +} + bool CConnman::DisconnectNode(NodeId id) { LOCK(cs_vNodes); for (CNode *pnode : vNodes) { diff --git a/src/net_processing.cpp b/src/net_processing.cpp --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3402,14 +3402,15 @@ } else if (pnode->m_manual_connection) { LogPrintf("Warning: not punishing manually-connected peer %s!\n", pnode->addr.ToString()); - } else { + } else if (pnode->addr.IsLocal()) { + // Disconnect but don't ban _this_ local node + LogPrintf("Warning: disconnecting but not banning local peer %s!\n", + pnode->addr.ToString()); pnode->fDisconnect = true; - if (pnode->addr.IsLocal()) { - LogPrintf("Warning: not banning local peer %s!\n", - pnode->addr.ToString()); - } else { - connman->Ban(pnode->addr, BanReasonNodeMisbehaving); - } + } else { + // Disconnect and ban all nodes sharing the address + connman->Ban(pnode->addr, BanReasonNodeMisbehaving); + connman->DisconnectNode(pnode->addr); } return true; } @@ -3476,6 +3477,7 @@ // Make sure we ban where that come from for some time. connman->Ban(pfrom->addr, BanReasonNodeMisbehaving); + connman->DisconnectNode(pfrom->addr); pfrom->fDisconnect = true; return false; @@ -3508,6 +3510,7 @@ hdr.pchChecksum + CMessageHeader::CHECKSUM_SIZE), pfrom->GetId()); connman->Ban(pfrom->addr, BanReasonNodeMisbehaving); + connman->DisconnectNode(pfrom->addr); return fMoreWork; } diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -1390,6 +1390,7 @@ clientModel->getPeerTableModel()->getNodeStats(detailNodeRow); if (stats) { m_node.ban(stats->nodeStats.addr, BanReasonManuallyAdded, bantime); + m_node.disconnect(stats->nodeStats.addr); } } clearSelectedNode(); diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -685,10 +685,13 @@ absolute = true; } - isSubnet - ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) - : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, - absolute); + if (isSubnet) { + g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute); + g_connman->DisconnectNode(subNet); + } else { + g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute); + g_connman->DisconnectNode(netAddr); + } } else if (strCommand == "remove") { if (!(isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr))) {