-
Notifications
You must be signed in to change notification settings - Fork 38.7k
Execute Discover() when bind=0.0.0.0 or :: is set #31492
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
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code Coverage & BenchmarksFor details see: https://corecheck.dev/bitcoin/bitcoin/pulls/31492. 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. |
|
@andremralves Thanks for putting up this PR so that it helped me run the test on Mac. In addition to your changes, the full setup on mac would require comment made by @evgeniytar in #31293 (comment) , which I quote: So, the following tweak on lo0 is not required: Then run: Otherwise, it will hit error below: Let me know if a separated PR is preferable so that I can submit one after your PR is in. |
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.
Tested ACK a25ce3b22ff3b5771353ab4bcb66a932702bfbd1
Thanks for creating this PR @andremralves.
Log output at master@85bcfeea23568053ea09013fb8263fa1511d7123
Note: to reproduce, use the above code by @andremralves #31492 (comment)
Log output at commit a25ce3b22ff3b5771353ab4bcb66a932702bfbd1
For mac see the comment by @tnndbtc
P.S. I have also checked the following:
- if no
-bindis used then we are automatically binding 0.0.0.0, executeDiscover() -bindis used with either 0.0.0.0 or ::, executeDiscover()
|
@andremralves I also tested your PR on mac and provided comments in #31293 (comment) . This is a pass to me as I validated on Mac and checked workflow by adding more debug traces. |
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 changes are validated on Mac (15.1.1, Apple M1 chipset). Review comment is provided in #31293 (comment). But, still need to fix the merge conflict.
Agree with you, works on M2 chip as well!! |
Thank you for the review @tnndbtc and @i-am-yuvi. I will fix the merge conflicts. |
src/init.cpp
Outdated
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.
Hey, I'm reviewing this PR; can you please explain to me the thoughts behind removing this line of code?
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.
As onion_service_target will contain the one and only onion service target in this branch of logic, we don't need to explicitly add it to a list of onion service targets. This is especially true since connOptions.onion_binds is only used to make sure there is only one onion bind; we have already checked that above (line 1906).
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.
Hey, I'm reviewing this PR; can you please explain to me the thoughts behind removing this line of code?
Without this change the test case ./build/src/bitcoind --bind=0.0.0.0:port=onion would fail. Since we are now setting bind_on_any as true when -bind=0.0.0.0, the server would attempt to bind to 0.0.0.0:port two times in CConnman::InitBinds (lines 3272 and 3286). The addition in lines 3279-3296 handles the default bind for onion and fixes the issue.
Moved to draft. @andremralves are you circling back to fix the conflicts? |
Sorry for the delay! I've been a little bit busy lately, but I'll take care of the conflicts now. |
db30b9c to
8f753ec
Compare
|
🚧 At least one of the CI tasks failed. HintsTry to run the tests locally, according to the documentation. However, a CI failure may still
Leave a comment here, if you need help tracking down a confusing failure. |
8f753ec to
0db64fe
Compare
0db64fe to
9626c04
Compare
9626c04 to
1561575
Compare
|
Fixed the conflicts! |
|
Tested ACK 1561575 |
yuvicc
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.
re-ACK 1561575
- Tested all the changes
ryanofsky
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.
Code review ACK 1561575, but would be nice to have feedback from @vasild here since this is supposed to fix #31293.
The changes here all seem to make sense but the interactions between them are complicated. I think this PR would be easier to review if the changes could be broken down as much as possible. It would be nice to add new tests in a first commit to clarify current buggy behaviors. Then it seems like the GetListenPort =onion parsing fix could be a separate commit. Then the refactoring change replacing connOptions.onion_binds.push_back(onion_service_target) with new code in InitBinds could be a another commit. After that the main Discover/bind_on_any part of the change would more clear.
| struct in_addr onion_service_target; | ||
| onion_service_target.s_addr = htonl(INADDR_LOOPBACK); | ||
| const uint16_t onion_port = GetListenPort() + 1; | ||
| const CService onion_addr = {onion_service_target, onion_port}; // 127.0.0.1 |
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.
In commit "net: execute Discover() when bind=0.0.0.0 or :: is set" (c1de112)
Might be missing something, but it seems like this could be simplified:
const CService onion_addr{DefaultOnionServiceTarget(GetListenPort() + 1);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.
Right. This new code duplicates the code from DefaultOnionServiceTarget():
Lines 726 to 731 in 5b8046a
| CService DefaultOnionServiceTarget(uint16_t port) | |
| { | |
| struct in_addr onion_service_target; | |
| onion_service_target.s_addr = htonl(INADDR_LOOPBACK); | |
| return {onion_service_target, port}; | |
| } |
and the port logic from init.cpp:
Line 1926 in 5b8046a
| const uint16_t default_bind_port_onion = default_bind_port + 1; |
Which is problematic because if this logic has to be changed then it will have to be changed in more than one place.
Before this PR the outcome of DefaultOnionServiceTarget(default_bind_port_onion) was communicated to InitBinds() (here) via the entry in options.onion_binds. Adding that entry however was removed in this PR to facilitate the new condition above: options.bind_on_any && options.vBinds.empty() && options.onion_binds.empty() (onion_binds needs to be empty now).
I think a smaller, less invasive change can replace commit c1de112 net: execute Discover() when bind=0.0.0.0 or :: is set:
[patch] call Discover() also if -bind=0.0.0.0[:port] is configured
--- i/src/init.cpp
+++ w/src/init.cpp
@@ -1995,13 +1995,20 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
"for the automatically created Tor onion service."),
onion_service_target.ToStringAddrPort()));
}
StartTorControl(onion_service_target);
}
- if (connOptions.bind_on_any) {
+ // If -bind=0.0.0.0[:port] or -whitebind=0.0.0.0[:port] was configured.
+ // Deliberately omit -bind=0.0.0.0[:port]=onion (if configured) because that
+ // listening address should not be advertised.
+ const bool some_binds_are_any{
+ std::ranges::any_of(connOptions.vBinds, [](const CService& b) { return b.IsBindAny(); }) ||
+ std::ranges::any_of(connOptions.vWhiteBinds, [](const NetWhitebindPermissions& w) { return w.m_service.IsBindAny(); })};
+
+ if (connOptions.bind_on_any || some_binds_are_any) {
// Only add all IP addresses of the machine if we would be listening on
// any address - 0.0.0.0 (IPv4) and :: (IPv6).
Discover();
}
for (const auto& net : args.GetArgs("-whitelist")) {|
🐙 This pull request conflicts with the target branch and needs rebase. |
| struct in_addr onion_service_target; | ||
| onion_service_target.s_addr = htonl(INADDR_LOOPBACK); | ||
| const uint16_t onion_port = GetListenPort() + 1; | ||
| const CService onion_addr = {onion_service_target, onion_port}; // 127.0.0.1 |
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.
Right. This new code duplicates the code from DefaultOnionServiceTarget():
Lines 726 to 731 in 5b8046a
| CService DefaultOnionServiceTarget(uint16_t port) | |
| { | |
| struct in_addr onion_service_target; | |
| onion_service_target.s_addr = htonl(INADDR_LOOPBACK); | |
| return {onion_service_target, port}; | |
| } |
and the port logic from init.cpp:
Line 1926 in 5b8046a
| const uint16_t default_bind_port_onion = default_bind_port + 1; |
Which is problematic because if this logic has to be changed then it will have to be changed in more than one place.
Before this PR the outcome of DefaultOnionServiceTarget(default_bind_port_onion) was communicated to InitBinds() (here) via the entry in options.onion_binds. Adding that entry however was removed in this PR to facilitate the new condition above: options.bind_on_any && options.vBinds.empty() && options.onion_binds.empty() (onion_binds needs to be empty now).
I think a smaller, less invasive change can replace commit c1de112 net: execute Discover() when bind=0.0.0.0 or :: is set:
[patch] call Discover() also if -bind=0.0.0.0[:port] is configured
--- i/src/init.cpp
+++ w/src/init.cpp
@@ -1995,13 +1995,20 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
"for the automatically created Tor onion service."),
onion_service_target.ToStringAddrPort()));
}
StartTorControl(onion_service_target);
}
- if (connOptions.bind_on_any) {
+ // If -bind=0.0.0.0[:port] or -whitebind=0.0.0.0[:port] was configured.
+ // Deliberately omit -bind=0.0.0.0[:port]=onion (if configured) because that
+ // listening address should not be advertised.
+ const bool some_binds_are_any{
+ std::ranges::any_of(connOptions.vBinds, [](const CService& b) { return b.IsBindAny(); }) ||
+ std::ranges::any_of(connOptions.vWhiteBinds, [](const NetWhitebindPermissions& w) { return w.m_service.IsBindAny(); })};
+
+ if (connOptions.bind_on_any || some_binds_are_any) {
// Only add all IP addresses of the machine if we would be listening on
// any address - 0.0.0.0 (IPv4) and :: (IPv6).
Discover();
}
for (const auto& net : args.GetArgs("-whitelist")) {| // If -bind= is provided with ":port" part, use that (first one if multiple are provided). | ||
| for (const std::string& bind_arg : gArgs.GetArgs("-bind")) { | ||
| constexpr uint16_t dummy_port = 0; | ||
| // maybe bind_arg has "=onion" | ||
| const std::string truncated_bind_arg = bind_arg.substr(0, bind_arg.rfind('=')); | ||
|
|
||
| const std::optional<CService> bind_addr{Lookup(bind_arg, dummy_port, /*fAllowLookup=*/false)}; | ||
| const std::optional<CService> bind_addr{Lookup(truncated_bind_arg, dummy_port, /*fAllowLookup=*/false)}; | ||
| if (bind_addr.has_value() && bind_addr->GetPort() != dummy_port) return bind_addr->GetPort(); | ||
| } |
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 this change to GetListenPort() will produce unwanted results if the configuration goes like:
-bind=1.1.1.1:1111=onion -bind=2.2.2.2:2222. In that case, I guess it should return 2222 like before this change, but after it, it would return 1111.
| if (index == std::string::npos) { | ||
| bind_addr = Lookup(bind_arg, default_bind_port, /*fAllowLookup=*/false); | ||
| if (bind_addr.has_value()) { | ||
| connOptions.bind_on_any |= bind_addr.value().IsBindAny(); |
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.
If the semantic of bind_on_any is to be changed then its comment deserves an update:
Lines 1072 to 1074 in 5b8046a
| /// True if the user did not specify -bind= or -whitebind= and thus | |
| /// we should bind on `0.0.0.0` (IPv4) and `::` (IPv6). | |
| bool bind_on_any; |
|
I've been working on this same issue and my findings align well with @vasild feedback for a simpler approach. Regarding the core fix: @vasild suggested approach is exactly right - the fix can be much simpler without the code duplication issues. Here's what I implemented successfully: // We should discover addresses in two cases:
// 1. When no -bind or -whitebind is specified (bind_on_any is true)
// 2. When any -bind address is 0.0.0.0 or ::
bool should_discover = connOptions.bind_on_any;
if (!should_discover) {
for (const auto& bind_addr : connOptions.vBinds) {
if (bind_addr.IsBindAny()) {
should_discover = true;
break;
}
}
}
if (should_discover) {
Discover();
}This avoids:
Regarding the test fix: I also resolved the The test now passes successfully with this approach. Happy to share the complete working implementation if helpful. |
|
@andremralves, what do you think about the above feedback? This PR is in "needs rebase" for about 2 months now, do you plan to work on it further? @b-l-u-e, if there is no activity here for some time, then at some point it would make sense to open a separate PR with your patch, up to your judgement. |
ACK on the approach, if there's no activity open a separate pr as suggested by @vasild ! |
SummaryThis PR can be closed as its taken up by #32757 with more better approach. |
|
Closing for now, due to inactivity. Please leave a comment, if you want this reopened and want to work on this again. You may also create a fresh pull request, referencing this one. |


If
-bind=0.0.0.0or-bind=::is specified, it indicates that we can bind to any available address. In this case, theDiscover()function should be executed to retrieve the local addresses. This behavior should also work for "=onion" addresses.I updated the
GetListenPort()function to also consider ports from onion address. Without this change, when-bind=0.0.0.0:port=onionis used, the bound port would not match the specified port.How to test
Prepare the addresses to be found by
Discover()Execute the test
Undo the changes after the test execution
Fixes #31293
This PR also fixes the test
feature_bind_port_discover.pythat was falling.Fixes #31336