-
Notifications
You must be signed in to change notification settings - Fork 37.7k
p2p: Don't self-advertise during version processing #26199
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, we would prepare to self-announce to a new peer while parsing a VERSION message from that peer. This is redundant, because we do something very similar in MaybeSendAddr(), which is called from SendMessages() after the version handshake is finished. There are a couple of differences: 1) MaybeSendAddr() self-advertises to all peers we do address relay with, not just outbound ones. 2) GetLocalAddrForPeer() called from MaybeSendAddr() makes a probabilistic decision to either advertise what they think we are or what we think we are, while PushAddress(self) on VERSION deterministically only does the former if the address from the latter is unroutable. 3) During VERSION processing, we haven't received a potential sendaddrv2 message from our peer yet, so self-advertisements with addresses from addrV2-only networks would always be dropped in PushAddress(). Since it's confusing to have two slightly different mechanisms for self-advertising, and the one in MaybeSendAddr() is better, remove the one in VERSION. Co-authored-by: Martin Zumsande <mzumsande@gmail.com>
Concept ACK |
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. 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. |
src/net_processing.cpp
Outdated
@@ -3274,39 +3274,16 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, | |||
m_num_preferred_download_peers += state->fPreferredDownload; | |||
} | |||
|
|||
// Self advertisement & GETADDR logic | |||
if (!pfrom.IsInboundConn() && SetupAddressRelay(pfrom, *peer)) { |
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.
SetupAddressRelay
used to have a misleading comment: "First addr message we have received from the peer, initialize m_addr_known". We were not receiving any addr messages from the peer here, yet we initialized it. It seems like this was the case from the beginning.- After this PR, calling
SetupAddressRelay
here seems unnecessary. If we drop it, the comment becomes valid :)
Although the inconsistency is a good signal the comment is confusing, so perhaps we should drop it. Not very useful anyway, at least the current code is pretty readable.
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.
So yeah: 1) Drop SetupAddressRelay
here; 2) Possibly drop the useless comment from SetupAddressRelay
?
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.
Alright, this has side-effects. MaybeSendAddr
(another self-ad) will stop working until we get an ADDR message from the peer (not the case before the change i suggest here).
Perhaps this code should be:
if (!pfrom.IsInboundConn()) {
SetupAddressRelay(pfrom, *peer);
....
}
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.
I think the current code is correct, SetupAddressRelay
here has three tasks:
- Initialize
m_addr_known
for outbound peers (unless block-relay-only), see [p2p] Reduce addr blackholes #21528 - Prevent Self-Advertisements to block-relay-only outbound peers (for which
SetupAddressRelay
returns false) - Prevent a GETADDR to block-relay-only outbound peers
Since 1) and 3) are still valid after this PR, I think we both need to keep calling SetupAddressRelay
and skip if it returns false.
I think this should be documented better (I had to revisit 21528 to recall how it worked while preparing this PR), so I will add some more documentation for this soon.
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 refactoring I suggested in my last message here is indeed wrong, because it ignores the returned value.
Do you agree that the comment inside SetupAddressRelay
is wrong though? That's the only thing that remains worrying me.
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.
Do you agree that the comment inside
SetupAddressRelay
is wrong though?
Yeah, it's incomplete because it only applies to inbound peers. I added documentation there and before the call to SetupAddressRelay
during version processing (as a second commit, because it's not directly related to the changes).
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.
nit: "Prevent GETADDR from being sent" sounds very complicated, and also might have additional unnecessary meaning of pro-actively preventing something.
I'd say "Don't send GETADDR [...]" is better. Feel free to ignore.
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.
missed this comment, changed wording now.
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.
agreed that the comment in SetupAddressRelay
was misleading. thanks for catching / fixing. I didn't hunt down the history, but I bet that was my fault 😅
RE current comment about "Don't send GETADDR...":
I find it a bit confusing, because we're also not sending GETADDR
message to inbound peers. maybe this code is too dense and is better communicated in a bit more verbose manner?
eg. in non-syntax-adhering code:
bool send_getaddr = false;
if (!pfrom.IsInboundConn()) {
send_getaddr = SetupAddressRelay();
}
if (send_getaddr){
// do GETADDR stuff
}
also cool if you want to skip the refactor and just want to update the comment to something like..
// Initialize address relay for all outbound peers
// Send GETADDR to non-block-relay-only outbound peers
I wish we had a better way to refer to non-block-relay-only outbound peers 😬
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.
I agree that it this would be better to understand if it's a bit more spread out, so I took your suggestion and changed the comment - hopefully it's clear now?
Concept ACK |
I dunno if I'm supposed to ACK this since this is my commit, but I approve the changes 3c43d9d I guess :) An easy way to look at this change is to notice that this code is almost entirely a subset of One real difference this could make is that due to the "makes a probabilistic decision to either advertise what they think we are or what we think we are" of this behavior, we could have ended up having two self-ads in one ADDR message (one added here, one added in UPD: Another important difference could be the time between the two calls. This might make sense if there's a risk of someone inserting our self-ad ( |
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
Yes, advertising both addresses is something that can happen, but only in a few cases:
I think I don't understand this completely, but the time between advertising during version message and |
ACK 24608c2 |
24608c2
to
1002cd1
Compare
code review ACK 1002cd1. this PR improves the encapsulation of self-advertisement logic, which simplifies the code as well as our mental models of addr relay on the network.
Agreed, but I'd take it slightly further. I think there is no difference in when the advertisement would actually occur. the My understanding of this PR is that there would be no tangible behavioral differences in the cases where the Since the I think the only time this would cause a connectivity issue is if your peers are somehow reporting your address to be something that can't be connected to, and you would have advertised something usable with
For the reasons I stated above, I agree. Advertising both seems unnecessary, and the worst case should just be slower time for inbounds to connect to you? @mzumsande @naumenkogs curious to hear your feedback. do these claims track with your understanding? |
src/net_processing.cpp
Outdated
@@ -3274,39 +3274,16 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, | |||
m_num_preferred_download_peers += state->fPreferredDownload; | |||
} | |||
|
|||
// Self advertisement & GETADDR logic | |||
if (!pfrom.IsInboundConn() && SetupAddressRelay(pfrom, *peer)) { |
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.
agreed that the comment in SetupAddressRelay
was misleading. thanks for catching / fixing. I didn't hunt down the history, but I bet that was my fault 😅
RE current comment about "Don't send GETADDR...":
I find it a bit confusing, because we're also not sending GETADDR
message to inbound peers. maybe this code is too dense and is better communicated in a bit more verbose manner?
eg. in non-syntax-adhering code:
bool send_getaddr = false;
if (!pfrom.IsInboundConn()) {
send_getaddr = SetupAddressRelay();
}
if (send_getaddr){
// do GETADDR stuff
}
also cool if you want to skip the refactor and just want to update the comment to something like..
// Initialize address relay for all outbound peers
// Send GETADDR to non-block-relay-only outbound peers
I wish we had a better way to refer to non-block-relay-only outbound peers 😬
oops, didn't post last night - just some suggestions around language in the comments. not essential to incorporate. |
This was the initial purpose of the PR, yeah. In my reading of your comment, I'm not sure it "takes further" in that sense. My finding was more niche (again, probably very hypothetical) — if only the latter call is in place, the data could be hijacked. Trying to make sure we're on the same page :) I agree with the rest of your comment. |
This code was a bit hard to understand, so make it less dense and add more explanations. Doesn't change behavior. Co-authored-by: Amiti Uttarwar <amiti@uttarwar.org>
1002cd1
to
956c670
Compare
1002cd1 to 956c670: Applied suggestions by @amitiuttarwar to second commit - thanks!
yes, I agree!
I didn't understand this the first time, but I think I do now - you mean an attacker could continuously spam us with our own address from other connections (but with bad metadata), and thus prevent us from sending our self-advertisement (with correct metadata) to new peers because they'd inserted a duplicate in between our processing of the version messages and us getting to I will have to think about this a bit more, but even if the timing issues and rate-limiting issues were solved, it would probably be really hard / impossible to that because of the way |
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. I went through the self advertisement logic and couldn't think of any concerning behavioral change this PR might induce. I do have a couple of questions though.
- There were some entries in my node's debug.log where the peer would send incorrect entries(here, the peer's own address/they could be tampered with) for what address the peer thinks we are (
vRecv >> addrMe
).- with the version processing mechanism, we'd self advertise our correct address at least once. (
GetLocalAddress
) - with the
MaybeSendAddr
mechanism, we'd sometimes self advertiseaddrMe
(what peer thinks we are/could be tampered with) only. (GetLocalAddrForPeer
) - The connections would last for only a short duration though(around 4 mins). Could this scenario be problematic?
- with the version processing mechanism, we'd self advertise our correct address at least once. (
- even if we don't accept inbound connections, we still self-advertise. is it because we can't detect them?
I think that it's not possible to say in general which address (the local or peer's one) is better, or "correct". In some cases, the peer may have a better idea how we are reachable than we do. In other cases, it's the other way round, or maybe neither are working if we're just not reachable by others. Also note that if we overrule our own local address and advertise with the address a peer sees us with, we'll only do that back to that same peer. We never send an
If we explicitly disable inbound connections ( |
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.
@naumenkogs @mzumsande
thanks for the feedback. I think I now better understand the hypothetical issue in terms of when we queue up the addresses internally, not when we actually trigger the message. due to the various mechanisms Martin mentioned, I think most viable attacks would be mitigated.
reACK 956c670
ACK 956c670 |
ACK 956c670 |
956c670 refactor, doc: Improve SetupAddressRelay call in version processing (Martin Zumsande) 3c43d9d p2p: Don't self-advertise during VERSION processing (Gleb Naumenko) Pull request description: This picks up the last commit from bitcoin#19843. Previously, we would prepare to self-announce to a new peer while parsing a `version` message from that peer. This is redundant, because we do something very similar in `MaybeSendAddr()`, which is called from `SendMessages()` after the version handshake is finished. There are a couple of differences: 1) `MaybeSendAddr()` self-advertises to all peers we do address relay with, not just outbound ones. 2) `GetLocalAddrForPeer()` called from `MaybeSendAddr()` makes a probabilistic decision to either advertise what they think we are or what we think we are, while `PushAddress()` on `version` deterministically only does the former if the address from the latter is unroutable. 3) During `version` processing, we haven't received a potential sendaddrv2 message from our peer yet, so self-advertisements with addresses from addrV2-only networks would always be dropped in `PushAddress()`. Since it's confusing to have two slightly different mechanisms for self-advertising, and the one in `MaybeSendAddr()` is better, remove the one in `version`. ACKs for top commit: stratospher: ACK 956c670 naumenkogs: ACK 956c670 amitiuttarwar: reACK 956c670 Tree-SHA512: 933d40615289f055c022170dde7bad0ac0a1d4be377538bfe9ba64375cfeb03bcd803901591f0739ac4850c880e8475a68fd1ab0330800030ab7f19e38c00274
This picks up the last commit from #19843.
Previously, we would prepare to self-announce to a new peer while parsing a
version
message from that peer.This is redundant, because we do something very similar in
MaybeSendAddr()
, which is called fromSendMessages()
afterthe version handshake is finished.
There are a couple of differences:
MaybeSendAddr()
self-advertises to all peers we do address relay with, not just outbound ones.GetLocalAddrForPeer()
called fromMaybeSendAddr()
makes a probabilistic decision to either advertise what they think we are or what we think we are, whilePushAddress()
onversion
deterministically only does the former if the address from the latter is unroutable.version
processing, we haven't received a potential sendaddrv2 message from our peer yet, so self-advertisements with addresses from addrV2-only networks would always be dropped inPushAddress()
.Since it's confusing to have two slightly different mechanisms for self-advertising, and the one in
MaybeSendAddr()
is better, remove the one inversion
.