Skip to content

net: advertise -externalip addresses#34538

Merged
achow101 merged 4 commits into
bitcoin:masterfrom
willcl-ark:onlynet-advertisments
Jul 14, 2026
Merged

net: advertise -externalip addresses#34538
achow101 merged 4 commits into
bitcoin:masterfrom
willcl-ark:onlynet-advertisments

Conversation

@willcl-ark

@willcl-ark willcl-ark commented Feb 9, 2026

Copy link
Copy Markdown
Member

-onlynet is documented to restrict automatic outbound connections, but it also currently prevents -externalip addresses from being advertised when their network is not in the -onlynet set. This happens because AddLocal() rejects addresses outside g_reachable_nets, regardless of whether the address was explicitly configured by the user.

Previous attempts to fix this (#24835 and #25690) removed the g_reachable_nets check from AddLocal().

This PR instead adds an explicit add_even_if_unreachable argument to AddLocal(). The argument defaults to false, and is set to true only when adding addresses from -externalip.

As a result, explicitly configured -externalip addresses can still be advertised even when their network is excluded by -onlynet, while discovered, mapped, bound, Tor control, and I2P SAM addresses continue to use the existing reachable-network filter.

This keeps the fix scoped to -externalip and addresses the concern raised in #25690:

I think it might also be weird for a user to activate -onlynet and keep on advertising their clearnet address to the network

The branch adds unit coverage for AddLocal() and functional coverage in p2p_addr_selfannouncement.py for -onlynet=ipv4 -externalip=<onion>.

Fixes: #25336
Fixes: #25669

@DrahtBot DrahtBot added the P2P label Feb 9, 2026
@DrahtBot

DrahtBot commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Code Coverage & Benchmarks

For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/34538.

Reviews

See the guideline and AI policy for information on the review process.

Type Reviewers
ACK mzumsande, w0xlt, achow101
Concept ACK chriszeng1010
Stale ACK seduless, vasild

If your review is incorrectly listed, please copy-paste <!--meta-tag:bot-skip--> into the comment that the bot should ignore.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #35027 (net: add -outboundbind option for outgoing source address by 8144225309)

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.

@willcl-ark

Copy link
Copy Markdown
Member Author

cc @mzumsande @vasild

I've taken a very slightly different approach at fixing this, and would value your opinion(s) on :)

@chriszeng1010 chriszeng1010 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested ACK

Built and rantest_bitcoin --run_test=net_testson Windows/MSYS2. New addlocal_onlynet_externalip test passes.

@seduless seduless left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested ACK 383763f

Reproduced #25336 on regtest: started a node with -onlynet=ipv4 -externalip=<onion_address>, confirmed getnetworkinfo shows empty localaddresses on master. With the fix applied, the onion address appears at score 4.

Traced all LOCAL_MANUAL callers and found no inconsistency with IsPeerAddrLocalGood.

Comment thread src/test/net_tests.cpp Outdated
@DrahtBot DrahtBot requested a review from chriszeng1010 March 3, 2026 04:04
@willcl-ark willcl-ark force-pushed the onlynet-advertisments branch from 383763f to 6e73dcf Compare March 3, 2026 10:01

@seduless seduless left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re-ACK 6e73dcf

@vasild vasild left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 6e73dcf

Note that AddLocal(..., LOCAL_MANUAL) is called from 3 places:

  1. For addresses given to -externalip=..., the focus of this PR.
  2. For our listening Tor address that is automatically created with the Tor router when -listenonion=1. So this setup will be affected by this PR: -onlynet=ipv4 -listenonion=1. Before this PR we would not advertise the Tor address and now we will.
  3. For our listening I2P address that is created with the I2P SAM proxy when -i2psam=... -i2pacceptincoming=1 is used. Similarly to Tor this would affect -onlynet=ipv4 -i2psam=... -i2pacceptincoming=1.

I think those 2. and 3. are welcomed changes. Maybe deserve a release note.

Will resolve #25669

Comment thread src/test/net_tests.cpp Outdated
Comment on lines +1582 to +1584
RemoveLocal(addr_onion);
g_reachable_nets.Add(NET_ONION);
fDiscover = true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is an attempt to restore the global state to what it was at the beginning of the test. Here are more robust ways to that:

For g_reachable_nets:

... test ...
// Assumes that g_reachable_nets was in its default-constructed state at the start of the test.
g_reachable_nets.Reset();

or (no assumptions)

const auto reachable_nets_at_start{g_reachable_nets.All()};
... test ...
g_reachable_nets.RemoveAll();
for (const auto& net : reachable_nets_at_start) {
    g_reachable_nets.Add(net);
}

For fDiscover:

const bool discover_orig{fDiscover};
... test ...
fDiscover = discover_orig;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, thanks, I agree. I changed the test to restore both global states as you suggested, in e459f65

@willcl-ark willcl-ark force-pushed the onlynet-advertisments branch from 6e73dcf to 3c63971 Compare March 5, 2026 12:18
@willcl-ark

Copy link
Copy Markdown
Member Author

I think those 2. and 3. are welcomed changes. Maybe deserve a release note.

😃 Release note added in 3c63971

@vasild vasild left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 3c63971

@DrahtBot DrahtBot requested a review from seduless March 5, 2026 12:33
@vasild

vasild commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

Might want to add "Fixes: #25669" to the OP.

@seduless seduless left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re-ACK 3c63971

@sedited sedited requested review from ajtowns and removed request for chriszeng1010 March 19, 2026 17:14
@ajtowns

ajtowns commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Might be better to set a bit somewhere for -externalip addresses rather than reusing score? Otherwise it seems possible that setting up a private node and then having some controlled peers connect to it would result in the score eventually being bumped above the LOCAL_MANUAL level and you'd start unexpectedly advertising your ip automatically, which might be a footgun for some.

The configuration and expected/implicit behaviours here seem very confusing and fragile in general here; eg I think this code is (or reads as-if it is) treating IsRoutable as "will packets sent to/from here have any chance of arriving?" while other parts of the code are using it as the -onlynet "should we make outbound connections to this part of the internet?"

@vasild vasild left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 7b28ef4

Show Signature
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

ACK 7b28ef41495f57d5b8f3fa67d467c16b0660b331
-----BEGIN PGP SIGNATURE-----

iQQzBAEBCAAdFiEE5k2NRWFNsHVF2czBVN8G9ktVy78FAmnc9GUACgkQVN8G9ktV
y7+ZJh//Zu1zi8Nw9TRVdTs4570wepmtW+Q111PgjBnhtogGa06gn2Qp5ootOu71
EILvuN4XUFj16UhQ25ZXGaFjmozGSVlWkG54Rr92wjOGxkb8jEXoLmtwgoUoEpWG
n6eUEUYKJ3xuwwCCgAmJTJc8Rxa/AIMSC5Qok0h+2DcoF5ff/+T4SoB2vs5xJllA
VtokRm0nQbjV/oq2MvFcWTcgS6M0nKKQmKNmWuEwG8Q5Is4vN/xergGvPN7VkeNu
WCHAz6N7LnWMwU6sqSQBrOEvGWB32xxdqSnq0JoAL1ZCvhOJcZxXMSCrhNdri2FS
VWnGBNc8VwJotnIfshu/rR/p+TU+C43j7HsfV9gj+Y4FG971T2fTOzEa4n8Zvc0h
a5JqexmXgurZNnqas0qsgbv+KymW2KCFzua7zccG2/PdLKf29HGf/w8uGiFe86ZU
h7fDfjshXDTzck85r3niEZXxPBDrpt1/HeDFwW4FfK5EANgQhdTAGKzxwE6AIPMf
BV1yPWIUJNFqZzvkuG4GbitTbpCjM9bV5O+6X/5d54shFdvRG7z1WYorC7tyutbo
CyAYXRkppCjjQkZ3i4c4TsVoYE0H+Qc9BS0cIen83Yi3/eyw9ViwZ5E37xf9+F36
AiN1PbzcsrUSiFBk5FM1VlNohhMNr3N885rjIyBDc2QCeS5FZ4/jm7DD1ItOERaH
uux8roTCoaKlRkq0o0yxG9HbC2sxnJs/fa+MaKttWDaSvyqUotCfOSLiEzPShfHU
OQ8NUOot1NeD/FBXhta6njptHpsy5075WLpGpQPF/QKrFDOZPxl/GTjrgPo0I//o
X2KFRlBDMTBhYiEK5Hx0clRjqWW/gN5kqjCS7zGgZH0Vada6ohwuu7X3f7kMyBfH
HqchUK9cen5I2UNoOPjMt3tvYZwbWWteYL5J2bqgOjrohFihC8uf8eKvHMf0gwFV
oO/D1nu3IfqI3UXbIEgy2p5j3hActfC8Fa71LrSf07f0rgrG6TY3PGf1csqFLxgL
XI8cnJSY06F2kvQERTJ2gVBzSBuqeU7tz3jWe4BxOAZwrlVTLytxsQGpPS6QzgR6
glyD9jURPaEfBdieAw78RWTb7VL4R2dy4LXqx2zotGXNsicdj5paUuRUimCV6GMP
8bHJBcHClMFpFsPkBR+u8sNZji0p+umJKI8WJr+/PYQknZui6JmJRpLjbmydYe3h
qpjU6H/Co4aqV6ch/j13O0C19WkrBAwlubPztevmAoHZhh3ugg344Iy8u8McFREa
VSl+zGaeicGed5GnkhGxG8RBjdZMa0AI+MhEEFGvGgFUqjLLcoGdmHEMVzLUbV3L
gB/T6GCym0hKjz6rT3gDUrhy7dsG8g==
=Sl7e
-----END PGP SIGNATURE-----

vasild's public key is on openpgp.org

Comment thread src/net.cpp Outdated

// learn a new local address
bool AddLocal(const CService& addr_, int nScore)
bool AddLocal(const CService& addr_, int nScore, bool fExternalIP)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming, feel free to ignore:

The linkage between this argument and the -externalip configuration option is only outside of the AddLocal() function. So, looking at the function alone and not its callers, the name fExternalIP is odd.

From the point of view of the AddLocal() function, the meaning of its new argument is "ignore reachable nets" or "add even if unreachable". It is better to name it after that.

This would show in the future if there is a new caller of AddLocal() who wants to pass true to "add even if unreachable" for a reason other than that the address comes from -externalip. Then the caller would have to use /*fExternalIP=*/true even if he has nothing to do with -externalip.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I addressed both of your review points at once by renaming the new param to add_even_if_unreachable in b187434

Comment thread src/net.cpp Outdated
}

bool AddLocal(const CNetAddr &addr, int nScore)
bool AddLocal(const CNetAddr& addr, int nScore, bool fExternalIP)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding and preference is that we follow the naming convention regardless of surrounding code that might use the old convention. That is, name the new parameter external_ip instead of fExternalIP. Then, if you want, in another commit, for consistency rename nScore to score.

@DrahtBot DrahtBot requested a review from seduless April 13, 2026 14:02
@willcl-ark willcl-ark force-pushed the onlynet-advertisments branch from 7b28ef4 to d63f6a9 Compare April 30, 2026 11:13

@vasild vasild left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK d63f6a9

Show Signature
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

ACK d63f6a97bf1e16305c1044e8b0bd7dff015966ec
-----BEGIN PGP SIGNATURE-----

iQQzBAEBCAAdFiEE5k2NRWFNsHVF2czBVN8G9ktVy78FAmnzUA0ACgkQVN8G9ktV
y7++CB/+JRiXIJkDGHb7DTN7SI6Qo1Ru5J7YGYQ63wTSLSBoKK/gZw7W+T6ki38V
Dz6rB3hCwfkwFIiF9UWxTeVEvrpvk9znJbZ2nAXxjaYmy+op9TjH0C1qcTFRCH0B
Q/UxAVbivRIvZ/cFlaKHIBjwxvD5tFoAVczp8TKrdaFJLudt+z1MKxfWMXK4xuui
q9g/4ox1Qt3OupGpFrfqMcZfqYcx5+aOJm0M5MhUFhCLumnZhrjlOtnlNeJK/2kR
A+TSyaDi4NpZKyosR+O3DIyhWh72aUv+WbIWUZq/k3S4KJrkDdSwGdq+DTw54zxS
DJ74L2G5R7IclyidHIV4niZpR15VkmpbqmefKJZrQTHgnxyDn3SYuRfixX6UqgC3
c1x1kqLWNKaIS+D15VIXRIQ6C8HSiyX/+W1UqcYhyz3V8oq9wieKVrSusxdkuNYL
fbpFIlGj08rcRFqYiqNo7EF6wceyQy6/XAZO8Gs65tUQtchYvCqIF0TbsFA2Avmf
6fiW/tOgE8laq5/A4w8q6iRp89fNIBN8oCG1rJPyF5mnov8mp8ZJrpVAm/HZQWCN
+UJu5zil9GmwDpMRY+pUhli9x4o62AJjwY+FTzeiBthSzvcAitbL/CYIxw3A+Hqc
yQM3kJFo+tmdODudx47ytxIRhZQexZIE+t4PrK2id3GpD5/xmFiF9s1tJ8ceZ8H4
481O7mD6VgcNBzMK58k9d1GpH/IoYJExi5lwb50SvdRQ0udBTg+Lqmg7plvNJaNA
ZlAFtZ0hgctL57b/9lJ9h1g/WD8cjozTYCPJd1QFJtxU5o5/ohBnLKT8jdtCX4yQ
eQFexxS4b6LVOGQlO92mKdSVAEoYI4LjxFski60lio52ODLt2Fq0dYgugiafRG0z
ZLUuoBsN/AO7/D9IK5WSXIah6hLyAGUYFSoCG5vS+dyWkk532G52mtV/V9m4I16V
ORgjmUygHNMafjHsUjcNYFCmV5esJ8MKGXQisVGq/KP1II1mFaeJUKeNBE36oPXC
/Ai2ykCC5pJbqBHHnEm2ieHH5O6i2nazNul4MgKuuPj0wE8tmuAAtToXfDwcWSbc
37QxgV+Xmm98Hksx/4t3hVEOoKkdEaa66a3l8XoUvhDB1c/pqsWTlbWpMt5fqDIc
qoTVsTVeTAXhEWQNFYWD4+OXpG5GsO0lEABTB+vGtis4x06fhnNl9B/bBgUM5jNr
NFeczGcsfs3V0BO2RAzIHg+7jes/KsjkdB6OpxVtRBNA2kN6Jct9sgUvY0HXPWIc
2FBxhjJKKG0cepwooZ/5CTcmTOHHtavrxutuO4Ng3NbbekF6f0yFXwUSuuZ+kobq
ySi4Pw6X1oNSGB/Ig+dD2HGChVUZow==
=oZXa
-----END PGP SIGNATURE-----

vasild's public key is on openpgp.org

@willcl-ark

Copy link
Copy Markdown
Member Author

Might be better to set a bit somewhere for -externalip addresses rather than reusing score? Otherwise it seems possible that setting up a private node and then having some controlled peers connect to it would result in the score eventually being bumped above the LOCAL_MANUAL level and you'd start unexpectedly advertising your ip automatically, which might be a footgun for some.

The configuration and expected/implicit behaviours here seem very confusing and fragile in general here; eg I think this code is (or reads as-if it is) treating IsRoutable as "will packets sent to/from here have any chance of arriving?" while other parts of the code are using it as the -onlynet "should we make outbound connections to this part of the internet?"

I should have updated after my last push here, sorry. I think the current approach in d63f6a9 addresses the (correct) concerns you had: the reachable-net bypass is no longer derived from the stored local-address score, but is passed explicitly only from the -externalip init path. So peer observations can still change nScore, but cannot cause a non-externalip address to start bypassing -onlynet.

I considered adding persistent state to LocalServiceInfo, but it makes the AddLocal path a (tiny) bit more complicated and I don't see another user of that state. Do you know of one outside of this reachable-net decision? The diff wouldn't be large, but I think this is fine as it is here too.

Comment thread src/net.cpp

@mzumsande mzumsande left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK d63f6a9

I think the behavior of the current version may match user expectations best.

Though it still doesn't match the documentation of -onlynet ("Inbound and manual connections are not affected by this option.") when the automatic discovery is supppressed for non-reachable networks, including cases like -onlynet=ipv4 -listenonion=1.

Comment thread src/net.cpp
Prepare for letting explicitly configured local addresses bypass the
reachable-net filter without tying that behavior to LOCAL_MANUAL score.

Pass an `add_even_if_unreachable` bool through `AddLocal()`, defaulting
to `false`.
When -onlynet excludes a network, AddLocal() rejects local addresses
from that network. This also rejects addresses explicitly configured via
-externalip, so a configuration like -onlynet=ipv4 -externalip=<onion>
never advertises the onion address.

Set the AddLocal() unreachable-net override only when adding -externalip
addresses so the bypass remains limited to explicit user configuration.
Add unit coverage for the -onlynet/-externalip interaction.

Check that an unreachable address still fails with normal AddLocal()
arguments, while the same address succeeds when the unreachable-net
override is set for explicit local-address configuration.
Extend p2p_addr_selfannouncement to restart the node with -onlynet=ipv4
-externalip=<onion> and verify the onion address appears in
localaddresses despite its network being unreachable.
@willcl-ark willcl-ark force-pushed the onlynet-advertisments branch from d63f6a9 to dab7f2c Compare July 7, 2026 09:50
@willcl-ark

Copy link
Copy Markdown
Member Author

Though it still doesn't match the documentation of -onlynet ("Inbound and manual connections are not affected by this option.") when the automatic discovery is supppressed for non-reachable networks, including cases like -onlynet=ipv4 -listenonion=1.

I agree somewhat, but IMO listenonion=1 is a fair bit more ambiguous as it is automatically creating a service which, if advertised with a configuration like -onlynet=ipv4, might do something the user doesn't expect, if they consider themselves using onlynet as a privacy boundary.

@mzumsande mzumsande left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re-ACK dab7f2c

only commit messages changed

@DrahtBot DrahtBot requested a review from vasild July 7, 2026 13:28

@w0xlt w0xlt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK dab7f2c

@achow101

Copy link
Copy Markdown
Member

ACK dab7f2c

@achow101 achow101 merged commit 70d9ec7 into bitcoin:master Jul 14, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

externalip=...onion ignored when onion/prox not set Onlynet=ipv4 disables Tor advertisements

9 participants