-
Notifications
You must be signed in to change notification settings - Fork 38.7k
net: disconnect peers by address without using a subnet #20849
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Previously, when disconnecting a peer with a given address we would create a dummy subnet that contains just 1 address (/32 for IPv4 and /128 for IPv6) and would disconnect all peers that belong to this subnet (there may be more than one connection, to a different port). The problem is that for any non-IPv4 and non-IPv6 address we would create an invalid subnet which would later not match any addresses. Thus, don't use a one-host-subnet, but compare the addresses directly. This works for any type of addresses.
|
The problem was discovered by @MarcoFalke. |
|
tested-only ACK 5fd2cee did not review the code 🔮 Show signature and timestampSignature: Timestamp of file with hash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code review ACK 5fd2cee
It would be good to have a failing test case that this patch fixes, either unit tests or in the functional rpc_setban or p2p_disconnect_ban ones.
|
#20852 contains a fix for this issue + it also fixes a similar issue in |
|
Any tips how to test this manually? Disconnecting outbound onion peers with |
|
@jonatack yes, the
|
This comment has been minimized.
This comment has been minimized.
|
Adding logging to the code path and verified that Logging added to master and to this patch: @@ -2805,6 +2805,7 @@ bool CConnman::DisconnectNode(const CSubNet& subnet)
LOCK(cs_vNodes);
for (CNode* pnode : vNodes) {
if (subnet.Match(pnode->addr)) {
+ LogPrintf("Disconnecting %s via subnet peer=%d address=%s network=%s\n",
+ pnode->ConnectionTypeAsString(), pnode->GetId(),
+ pnode->addr.ToString(), GetNetworkName(pnode->ConnectedThroughNetwork()));
pnode->fDisconnect = true;
disconnected = true;
}Logging also added to this patch: @@ -2818,6 +2819,7 @@ bool CConnman::DisconnectNode(const CNetAddr& addr)
LOCK(cs_vNodes);
for (CNode* pnode : vNodes) {
if (addr == pnode->addr) {
+ LogPrintf("Disconnecting %s via addr peer=%d address=%s network=%s\n",
+ pnode->ConnectionTypeAsString(), pnode->GetId(),
+ pnode->addr.ToString(), GetNetworkName(pnode->ConnectedThroughNetwork()));
pnode->fDisconnect = true;
disconnected = true;
}On master, disconnection fails and nothing is logged. With this patch, the peer is immediately removed from the -netinfo 4 peers dashboard and the log shows: Upgrading to tested ACK 5fd2cee |
Change the `peer_discouragement` test to use `CNode` pointers so that the nodes it uses can be added to `CConnman::vNodes` and cleaned up properly. Make it use `CConnmanTest` instead of `CConnman`. This is needed because we want to check `CNode::fDisconnect` and for this flag to be flipped by `CConnman::DisconnectNode()` the node must be in `CConnman::vNodes`. Extend the test with one torv3 peer and check that it is discouraged and disconnected as expected.
|
Appended an extra commit with unit test that fails on If it does not get re-ACKs or if it turns out to be problematic I will remove it, restoring the already ACK'ed commit id. |
|
Nice, will review asap. |
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 98140bc code review, manual testing with setban OUTBOUND_ONION add, and verified the new test fails on master on the non-IP Tor v3 peer disconnection assertion.
| BOOST_CHECK(banman->IsDiscouraged(addr2)); | ||
| BOOST_CHECK(banman->IsDiscouraged(addr3)); | ||
| for (CNode* node : nodes) { | ||
| BOOST_CHECK(node->fDisconnect); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new test code fails at the right place on master
test/denialofservice_tests.cpp(292): info: check banman->IsDiscouraged(addr1) has passed
test/denialofservice_tests.cpp(293): info: check banman->IsDiscouraged(addr2) has passed
test/denialofservice_tests.cpp(294): info: check banman->IsDiscouraged(addr3) has passed
test/denialofservice_tests.cpp(296): info: check node->fDisconnect has passed
test/denialofservice_tests.cpp(296): info: check node->fDisconnect has passed
test/denialofservice_tests.cpp(296): error: in "denialofservice_tests/peer_discouragement": check node->fDisconnect has failed
test/denialofservice_tests.cpp(222): Leaving test case "peer_discouragement"; testing time: 32905us
nit, maybe not worth it for tests, could use nodes.at() notation for bounds checking instead of nodes[]
| bool CConnman::DisconnectNode(const CNetAddr& addr) | ||
| { | ||
| return DisconnectNode(CSubNet(addr)); | ||
| bool disconnected = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this change still needed with #20852? It seems to me that makes the old, much more compact, construction work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, if #20852 is merged, then this PR is not needed, see #20849 (comment).
I first opened this PR to fix DisconnectNode() and then realized that the same problem exists in BanMan, thus opened #20852 which fixes both by modifying CSubNet.
Maybe this PR could be preferred as less risky compared to #20852. It is ok if this is merged first and later #20852 is also merged - they do not conflict and both go in master.
|
Just to elaborate on the relationship between #20849 and #20852: The problem in #20849 fixes #20852 changes About the release, maybe the following makes sense: Include #20849 in the next rc and in the Later, if #20852 is merged (ever) there is no need to revert #20849. |
|
It might be better to wait for #20852 (0.21.1), after which this is not needed. |
maflcko
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK on adding the test. Mind to open a new pull for this?
|
The test is included in #20904. |
Previously, when disconnecting a peer with a given address we would
create a dummy subnet that contains just 1 address (/32 for IPv4 and
/128 for IPv6) and would disconnect all peers that belong to this
subnet (there may be more than one connection, to a different port).
The problem is that for any non-IPv4 and non-IPv6 address we would
create an invalid subnet which would later not match any addresses.
Thus, don't use a one-host-subnet, but compare the addresses directly.
This works for any type of addresses.