Skip to content

net: option to disallow v1 connection on ipv4 and ipv6 peers#30951

Open
stratospher wants to merge 5 commits into
bitcoin:masterfrom
stratospher:v2-only-option
Open

net: option to disallow v1 connection on ipv4 and ipv6 peers#30951
stratospher wants to merge 5 commits into
bitcoin:masterfrom
stratospher:v2-only-option

Conversation

@stratospher
Copy link
Copy Markdown
Contributor

@stratospher stratospher commented Sep 23, 2024

resolves #29618.

This PR adds a config flag option -v2onlyclearnet which disallows outbound v1 connections on ipv4 and ipv6 networks since they're unencrypted. outbound v1 connections are still possible from tor/i2p/cjdns peers since they're encrypted networks.

  • v1 outbound connections to peers are not attempted
  • v1 reconnections are not attempted (if peer is falsely advertised as v2 peer and we attempt a v2 connection but it fails, we do not attempt a v1 reconnection when -v2onlyclearnet is switched on)

Currently 70% of reachable nodes in network supporting v2 (according to https://21.ninja/reachable-nodes/node-service-share/ and https://bitnodes.io/nodes). Also found 81% of addresses supporting v2 in the addrman of nodes I checked - personal node and the nodes in peer.observer. (You can use this branch to check the % of v2 addresses in a node's addrman.)

@DrahtBot
Copy link
Copy Markdown
Contributor

DrahtBot commented Sep 23, 2024

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/30951.

Reviews

See the guideline for information on the review process.

Type Reviewers
Concept NACK 1440000bytes
Concept ACK mzumsande, dergoegge, fjahr, sipa, kristapsk, laanwj, sedited, pinigapic-lang, davidgumberg
Approach ACK ajtowns
User requested bot ignore 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:

  • #35252 (net: send decoy transactions via private broadcast by andrewtoth)
  • #31260 (scripted-diff: Type-safe settings retrieval by ryanofsky)

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.

LLM Linter (✨ experimental)

Possible typos and grammar issues:

  • outbound connections on IPV4/IPV6 need to be v2 connections. -> outbound connections on IPv4/IPv6 need to be v2 connections. [IPV4/IPV6 is a misspelling of the protocol names]

Possible places where named args for integral literals may be used (e.g. func(x, /*named_arg=*/0) in C++, and func(x, named_arg=0) in Python):

  • node0.addnode("15.61.23.23:1234", "onetry", True) in test/functional/p2p_v2_encrypted.py
  • node0.addnode("8.8.8.8:1234", "onetry", False) in test/functional/p2p_v2_encrypted.py

2026-04-29 08:49:42

@vasild
Copy link
Copy Markdown
Contributor

vasild commented Sep 26, 2024

In #29618 and here, I don't see the motivation to forbid v1 connections. In other words, what is the purpose of this?

In addition to the concerns expressed in #29618, there is one more - if V2-only is widespread, it may be hard to eclipse V2-only node, but then it becomes easy to eclipse a V1 node which has a problem of finding peers to connect to, so an attacker starts a lot of nodes that do accept V1 connections.

I see possible downsides and 0 benefit of a v2only option.

@mzumsande
Copy link
Copy Markdown
Contributor

Concept ACK

In #29618 and here, I don't see the motivation to forbid v1 connections.

Well, to gain the benefits of BIP324. For example if you are concerned about someone inspecting the traffic to your node it really doesn't matter how many BIP324 peers you have if you have just one unencrypted connection. You could also run tor-only in this case, but that has its own disadvantages and -onlynet=onion shares the exact same downside that if everyone did it, the network would split. If some, but not all nodes who are running only on privacy networks would be willing to also have clearnet peers with this option, that would be a good thing in my opinion.

if V2-only is widespread

that would be a problem, but -onlynet, -blocksonly etc. have that exact same problem. I see this as an option you would only choose if you actually need it because you are concerned about unencrypted traffic.

@DrahtBot DrahtBot mentioned this pull request Sep 27, 2024
@jonatack
Copy link
Copy Markdown
Member

jonatack commented Sep 27, 2024

You could also run tor-only in this case, but that has its own disadvantages and -onlynet=onion shares the exact same downside that if everyone did it, the network would split.

Our docs address this to an extent here and here. As those docs point out, -onlynet only affects outbound connections (not inbound and manual ones), and we suggest that it be used with multiple networks. My blog goes further into it here and here.

If some, but not all nodes who are running only on privacy networks would be willing to also have clearnet peers with this option, that would be a good thing in my opinion.

Agree. My node, for instance, runs over tor/i2p/cjdns and makes manual connections to trusted clearnet peers.

if V2-only is widespread, it may be hard to eclipse V2-only node, but then it becomes easy to eclipse a V1 node which has a problem of finding peers to connect to, so an attacker starts a lot of nodes that do accept V1 connections.

Agree. With this change, clearnet node operators may need to accept v2, whether they wish to or not. We generally try to avoid forcing users to do things. I suppose my concept ack on this would depend on that tradeoff.

@vasild
Copy link
Copy Markdown
Contributor

vasild commented Sep 28, 2024

For example if you are concerned about someone inspecting the traffic to your node it really doesn't matter how many BIP324 peers you have if you have just one unencrypted connection.

True. Lets dive a bit deeper - what are the reasons to be concerned about somebody inspecting the traffic to my node?

Comment thread src/init.cpp Outdated
@@ -550,6 +550,7 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
argsman.AddArg("-i2pacceptincoming", strprintf("Whether to accept inbound I2P connections (default: %i). Ignored if -i2psam is not set. Listening for inbound I2P connections is done through the SAM proxy, not by binding to a local address and port.", DEFAULT_I2P_ACCEPT_INCOMING), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-onlynet=<net>", "Make automatic outbound connections only to network <net> (" + Join(GetNetworkNames(), ", ") + "). Inbound and manual connections are not affected by this option. It can be specified multiple times to allow multiple networks.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-v2transport", strprintf("Support v2 transport (default: %u)", DEFAULT_V2_TRANSPORT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-v2onlyclearnet", strprintf("Disallow v1 connections on IPV4/IPV6 (default: %u). Enabling this is not recommended unless absolutely necessary, as it may risk network partitions if all users enable it.", false), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
Copy link
Copy Markdown
Member

@jonatack jonatack Sep 28, 2024

Choose a reason for hiding this comment

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

Enabling this is not recommended unless absolutely necessary, as it may risk network partitions

This is unfortunately only one brigading campaign by one or more prominent bitcoiners on social media away from being potentially adopted by many nodes.

With -onlynet, the network partition risk is in practice opt-in, i.e. chosen by a minority subset for themselves. Whereas here, the network partitioning and the lack of peers risks could be imposed on a future minority of users that are running earlier versions of Bitcoin Core. This seems at odds with maintaining backward compatibility for that minority.

Comment thread src/net.h Outdated
@mzumsande
Copy link
Copy Markdown
Contributor

True. Lets dive a bit deeper - what are the reasons to be concerned about somebody inspecting the traffic to my node?

Some thoughts off the top my head:

  • You don't want others (e.g. network admins, internet providers, etc.) to know that you are running a bitcoin node at all. Maybe it's not allowed in your network / country etc., maybe for other reasons such as personal security.
  • Transaction privacy

In both of these cases, if you accept inbounds they could just connect to you as an alternative (but they would need to have a suspicion, whereas detection of bitcoin-related network data could be automated). So another alternative would be to only disallow v1 connections for outbound peers. In that case, if you don't want any v1 connections at all you'd have to run with -nolisten.

@vasild
Copy link
Copy Markdown
Contributor

vasild commented Sep 29, 2024

what are the reasons to be concerned about somebody inspecting the traffic to my node?

  • You don't want others (e.g. network admins, internet providers, etc.) to know that you are running a bitcoin node at all. Maybe it's not allowed in your network / country etc., maybe for other reasons such as personal security.

This is what is worrying me - V2-only will not hide the fact that I am running a bitcoin node, but may give the false impression that it does. This is dangerous. My node will connect to publicly known bitcoin nodes and the mere fact that I have a TCP connection to an addr:port, where it is known that a bitcoin node is running, is already revealing enough. No need to inspect the traffic itself.

Another possible misunderstanding is that V2-only makes the traffic impossible to spy. I can imagine a blatant MITM, which is detectable because the session keys would differ, should somebody bother to check them. Once I detect this, whom am I going to complain to? My oppressive gov/ISP/whatever, same one that is doing the spying? Or the ISP can outright redirect my connections to addr:port to their spy node at spyaddr:port (I think I am talking to addr, but addr does not even have a connection from me). The point is that the traffic is spyable. Then, what is it so much that I want to keep away from spies? The data being transferred is all public, except if we are talking about me broadcasting my own transactions, there you go:

  • Transaction privacy

V2-only may give the false impression that it breaks the link between transaction origin and IP address / geolocation. Even with unspyable p2p encryption, I may have a connection to a spy bitcoin node which then sees my traffic. Like you said "it really doesn't matter how many BIP324 peers you have if you have just one unencrypted connection" I think this is the same as "it does not matter even if all your connections are encrypted, if you have just one (encrypted) connection to a spy node".

@stratospher
Copy link
Copy Markdown
Contributor Author

@vasild V2 only doesn't protect against active attacks like the ones you've mentioned which require resources from the other party to run a node to spy the traffic.

V2 only protects against a cheaper attack vectors possible because of passive inspection of network traffic flowing through different medium. They don't need the other party to run a node to spy.

True. Lets dive a bit deeper - what are the reasons to be concerned about somebody inspecting the traffic to my node?

Some thoughts off the top my head:

  • You don't want others (e.g. network admins, internet providers, etc.) to know that you are running a bitcoin node at all. Maybe it's not allowed in your network / country etc., maybe for other reasons such as personal security.
  • Transaction privacy

Yes, for the same reason as wanting to encrypt network traffic in the first place and this just offers a stronger guarantee when running a node with v2 support that unencrypted clearnet bitcoin traffic is not being collected and sold by other parties. Deep packet inspection, keyword filtering are cheaper for ISPs/firewalls to pull off and v2 only would protect against this.

@vasild
Copy link
Copy Markdown
Contributor

vasild commented Oct 2, 2024

A V2-only option will:

  • not hide the fact that one runs bitcoin node (that is true regardless of encryption) and
  • not stop even moderately motivated actor from spying for transaction origin (either by opening a P2P connection to the target or bricking V2 encryption or outright redirecting connections to their node)

but it will give the false impression that it does those two things. Further, it will make it more difficult for old nodes to find peers to connect to.

Concept NACK because of that.

@dergoegge
Copy link
Copy Markdown
Member

Concept ACK

This option seems useful for users that want to:

  • prevent passive spying on their connections
  • increase the cost of tampering with the data exchanged on their connections
  • increase the cost of detecting that they run a bitcoin node

Currently 59.71% of network supports v2

Have you checked how diverse these ~60% of v2 supporting nodes are? An extreme example: if they are all on running on AWS then I don't think we should add the option at this time.

@vasild
Copy link
Copy Markdown
Contributor

vasild commented Oct 2, 2024

increase the cost of detecting that they run a bitcoin node

How? Given that the spy does not need to inspect the traffic at all:

My node will connect to publicly known bitcoin nodes and the mere fact that I have a TCP connection to an addr:port, where it is known that a bitcoin node is running, is already revealing enough.

@sipa
Copy link
Copy Markdown
Member

sipa commented Oct 2, 2024

@vasild That assumes the attacker has sufficient monitoring infrastructure in place to maintain an accurate list of Bitcoin P2P ip:ports. That's obviously not impossible, but it is a significantly larger effort than stateless packet inspection looking for the string "\xf9\xbe\xb4\xd9version\x00\x00\x00\x00\x00".

And yes, very little in BIP324 protects against an attacker deliberately targetting specific individuals - its goal is increasing costs for large-scale monitoring. From that perspective I agree there is a risk for a false sense of security when introducing options like these, but I think it's a stretch to say that that makes it pointless. I can very well imagine this makes it possible to run a node at all for some users.

However, as I pointed out in the linked issue, I am somewhat concerned about a potential future where it becomes harder for other/older software to connect to the network if large swaths move to be v2-only. Because of that, I wonder if it isn't better to make this only apply to outbound connections, and advise people who want more private operation to not listen for inbound connections.

@jonatack
Copy link
Copy Markdown
Member

jonatack commented Oct 2, 2024

However, as I pointed out in the linked issue, I am somewhat concerned about a potential future where it becomes harder for other/older software to connect to the network if large swaths move to be v2-only. Because of that, I wonder if it isn't better to make this only apply to outbound connections, and advise people who want more private operation to not listen for inbound connections.

Yes. I may be potentially concept/approach ack here if this proposal adopts the suggestion above / in #29618 (comment) or #29618 (comment). (Along with perhaps additional user documentation for node runners, maybe in the relevant config option helps and/or in /doc.)

@1440000bytes

This comment was marked as abuse.

@brunoerg
Copy link
Copy Markdown
Contributor

A mutation testing report for this PR is available at: https://brunoerg.xyz/mutation-core-front

@sedited
Copy link
Copy Markdown
Contributor

sedited commented Mar 11, 2026

Concept ACK

Afaict the project has communicated clearly that v2 encryption aims to protect against passive adversaries. It seems desirable to make good on that. Adding this to the 32 milestone.

@sedited sedited added this to the 32.0 milestone Mar 11, 2026
@pinigapic-lang
Copy link
Copy Markdown

Concept ACK

Copy link
Copy Markdown
Contributor

@fjahr fjahr left a comment

Choose a reason for hiding this comment

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

However this feels like lots of users setting listen=0 problem, and we're showing someone a reason for setting listen=0 + making that future slightly more probable. Will need to think more about this and curious about other people's thoughts on #30951 (review) as well.

Re-reading the code and @mzumsande's argument, I think I am now slightly leaning towards not tying it to listen=0 but rather only disallowing v1 connections. But I would still be fine with the current approach as well, especially if we can find a bit better wording.

Comment thread src/netbase.cpp Outdated
Comment thread src/net.h Outdated
Comment thread src/init.cpp Outdated

if (args.GetBoolArg("-v2onlyclearnet", DEFAULT_V2_ONLY_CLEARNET)) {
if (args.GetBoolArg("-listen", DEFAULT_LISTEN)) {
return InitError(_("Cannot set -v2onlyclearnet=1 with listen=0. Current listen=1 provides valuable network capacity. Use -v2onlyclearnet only if you truly need encrypted-only outbound traffic."));
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.

This error message is a bit confusing, first "Cannot set -v2onlyclearnet=1 with listen=0" seems to be wrong, it should say "listen=1" there (or s/with/without/). And then maybe switch the order of the current second and third sentence, I think that would read a bit better. For my taste the second sentence is a bit much because I don't think it's going to change anyone's mind but I would be fine to keep it. But we could also ask people to read the help text of the option carefully where we are more detailed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

oh whoops, thank you for the great catch!

maybe also makes sense to keep the error message short + keep the context only in the help text - it also prevents duplication. I've changed the error message to : "Cannot set -v2onlyclearnet=1 with listen=1. See -help for details on -v2onlyclearnet." open to better wordings/suggestions as well or if people feel we should give slightly more context.

Comment thread src/init.cpp
argsman.AddArg("-i2pacceptincoming", strprintf("Whether to accept inbound I2P connections (default: %i). Ignored if -i2psam is not set. Listening for inbound I2P connections is done through the SAM proxy, not by binding to a local address and port.", DEFAULT_I2P_ACCEPT_INCOMING), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-onlynet=<net>", "Make automatic outbound connections only to network <net> (" + Join(GetNetworkNames(), ", ") + "). Inbound and manual connections are not affected by this option. It can be specified multiple times to allow multiple networks.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-v2transport", strprintf("Support v2 transport (default: %u)", DEFAULT_V2_TRANSPORT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-v2onlyclearnet", strprintf("Ensure all outbound IPv4/IPv6 peers use encrypted network traffic (default: %u). Using this option requires -listen=0 and takes valuable listening capacity away from the network. Enable this option only if passive network observers like ISPs, firewalls, etc. pose a threat and unencrypted network traffic must be avoided. Note: Encryption protects message contents but does not obscure that you are running a Bitcoin node. Peers can still connect to you, observers can identify Bitcoin activity from connection attempts on the default port (8333) or from analysing Bitcoin network traffic patterns.", DEFAULT_V2_ONLY_CLEARNET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
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.

Not a strong opinion but as it is worded now, probably everyone who runs a bitcoin node will say, yes, these network observers are a problem for my privacy. It might be better to say something like: "if you are at risk of your traffic getting blocked or service shut down". That would be a bit more strongly steer people away from this if they don't know what they are doing/don't really need it. But it's just an idea, feel free to ignore.

Copy link
Copy Markdown
Contributor

@vasild vasild Apr 20, 2026

Choose a reason for hiding this comment

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

It might be better to say something like: "if you are at risk of your traffic getting blocked or service shut down"

If you are at such a risk, then -v2onlyclearnet=1 will not help. Mentioning "passive" is good because -v2onlyclearnet=1 protects only against "passive" observers and not against "active" ones who can MITM themselves and spy on the encrypted traffic. Then the user has no way to ensure that a possible adversary will stay "passive" and will not switch to "active" at any moment.

Comment thread src/net.cpp
Comment thread test/functional/p2p_v2_encrypted.py
only-clearnet condition is used in a few other places as well.
a boolean option `m_v2only_clearnet` is introduced in CConman
which will (in a later commit) store if the user wishes to
establish only outbound v2 connections on IPV4 and IPV6 networks
since they are unencrypted.

this option is accessible outside CConman using
`RequiresV2ForOutbound()` function with the IP address we're trying
to connect to passed as an argument.
if this option is set by the user, v1 connections on unencrypted
networks like IPV4/IPV6 will be disallowed. Only users with real
need are recommended to turn this on because it could risk network
partitioning in the unlikely scenario that everyone turns it on.
if `-v2onlyclearnet` is turned on,
- v1 addresses from addrman aren't selected and manual connections
aren't attempted for outbound connections if it's from IPV4/IPV6
networks.
- v1 downgrade mechanism is not attempted if v2 connection wasn't
successful
when `-v2onlyclearnet` is turned on:
- v1 connections to clearnet peers don't work
- v2 connections to clearnet peers work
- v1 connections to tor/i2p/cjdns peer works

a proxy is used because otherwise NET_UNROUTABLE is the default
network in the tests.
@stratospher
Copy link
Copy Markdown
Contributor Author

stratospher commented Apr 29, 2026

thank you for the great catch @fjahr! I've addressed your comments in this push. I've made the InitError message shorter but kept the help text as it is.

also summarising my understanding of the 2 implementation options possible for v2onlyclearnet in case it's helpful to reviewers:

purpose is assurance that passive observers can't see your encrypted traffic content (it doesn't hides the fact that you're running a Bitcoin node nor protect you from active adversaries)

Option A: outbound v2 only + no inbound connections (current PR) Option B: outbound + inbound v2 only connection
Flag interaction there's a flag interaction -v2onlyclearnet=1 requires -listen=0 no flag interaction
Outbound IPv4/IPv6 v2 only v2 only
Outbound Tor/I2P/CJDNS v1 and v2 (those networks encrypt anyway) v1 and v2 (those networks encrypt anyway)
Inbound IPv4/IPv6 none accepted since -listen=0 v2 only accepted
Inbound Tor/I2P/CJDNS none accepted since -listenonion=0 v1 and v2 accepted (those networks encrypt anyway)
Advantage no v1-only eclipse risk preserves listening capacity on the network
a user who doesn't want their traffic spied on probably shouldn't accept arbitrary inbounds either (in option B, it is upto the user to configure whether they want inbounds or not)
avoids easy detection that you're running a bitcoin node by stateless packet connection. (traffic analysis which is more effort will give you away) (in option B, listening nodes still advertise their IP on the network and is easier to discover compared to traffic analysis. traffic analysis which is more effort will give you away here as well.)
Disadvantage (hypothetical scenario when most of network switch on the option) total listening capacity on the network shrinks risk of eclipsing legacy v1-only nodes. if many nodes accept only v2 inbound, an attacker can cheaply spin up many v1-accepting nodes and dominate the v1 node's peer set.

which implementation option is better?

  1. hypothetical worst case scenario - option B wins here but don't think we should base our decision entirely on this. Let's say some day far in the future if there are <50 v1 nodes and a large fraction of the network turn on v2onlyclearnet
  • the network not having enough listening capacity since -v2onlyclearnet also forces -listen=0 (option A) is more dangerous than a v1 node not being able to connect to a v2 node and being eclipsed (option B).
  • chance of the hypothetical worst case scenario where most of the network turns on this flag is also unlikely. so don't think we should base our decision entirely on this. we already have a long list of opt-in flags that would be bad if huge fraction of network enabled them.
  1. user configurability - option A (or) B can win here
    • (option A) if user expects more to come along with the option - since passive adversaries can't read the message contents now - they might also expect passive adversary to not able to statelessly connect to them and detect their node.
    • (option B) if user likes to configure things themselves.
  2. option A wins here - there will be 1 extra condition in version message processing logic in net_processing for option B. we let them connect and while processing version message discover it's V1 and then disconnect. don't think it's important but just noting it here.
  3. option B wins here - more elegant in the sense that this option will naturally phase out and we can remove it in the far future when everyone is in v2 :)
  4. option A wins here - we don't want passive adversary statelessly connecting and detecting node.

I personally am ok with both. Maybe slight inclination to B since it gives the user configuration knob to do what they want. And we could document it in the help text to mention using listen=0 as well. Not sure what others prefer though.

Would love thoughts on what people prefer before changing approach/pushing an update :)

@andrewtoth
Copy link
Copy Markdown
Contributor

andrewtoth commented May 10, 2026

a user who doesn't want their traffic spied on probably shouldn't accept arbitrary inbounds either

Can you elaborate on how v2 without inbounds makes traffic analysis more difficult than v2 with inbounds? I'm not a traffic analysis expert, and to me it would make sense that any analysis happening on 10 v2 connections vs 125 v2 connections would come to the same conclusion about whether or not you were running a bitcoin node? I'm fairly sure I'm missing something though... :)

But otherwise I would lean towards requiring listen=0, since it would make node runners who were interested in providing inbound connections hesitate to turn this option on. Without requiring that, it seems too easy for everyone to just turn it on without considering existing v1 nodes.

Comment thread src/netbase.h
std::string GetNetworkName(enum Network net);
/** Return a vector of publicly routable Network names; optionally append NET_UNROUTABLE. */
std::vector<std::string> GetNetworkNames(bool append_unroutable = false);
bool IsClearnet(enum Network net);
Copy link
Copy Markdown
Contributor

@w0xlt w0xlt May 11, 2026

Choose a reason for hiding this comment

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

nit: A Doxygen comment can be added.

Suggested change
bool IsClearnet(enum Network net);
/** Returns true if the network is IPv4 or IPv6 (as opposed to a privacy network like Tor/I2P/CJDNS). */
bool IsClearnet(enum Network net);

Comment thread src/net.h
/** -listen default */
static const bool DEFAULT_LISTEN = true;
/** -v2onlyclearnet default */
static const bool DEFAULT_V2_ONLY_CLEARNET = false;
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.

nit:

Suggested change
static const bool DEFAULT_V2_ONLY_CLEARNET = false;
static constexpr bool DEFAULT_V2_ONLY_CLEARNET{false};

Comment thread src/net.h
* outbound connections on IPV4/IPV6 need to be v2 connections.
* outbound connections on Tor/I2P/CJDNS can be v1 or v2 connections.
*/
bool m_v2only_clearnet;
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.

If code ever reads m_v2only_clearnet before Init() is called, it's UB.

Suggested change
bool m_v2only_clearnet;
bool m_v2only_clearnet{false};

Comment thread src/init.cpp
argsman.AddArg("-i2pacceptincoming", strprintf("Whether to accept inbound I2P connections (default: %i). Ignored if -i2psam is not set. Listening for inbound I2P connections is done through the SAM proxy, not by binding to a local address and port.", DEFAULT_I2P_ACCEPT_INCOMING), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-onlynet=<net>", "Make automatic outbound connections only to network <net> (" + Join(GetNetworkNames(), ", ") + "). Inbound and manual connections are not affected by this option. It can be specified multiple times to allow multiple networks.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-v2transport", strprintf("Support v2 transport (default: %u)", DEFAULT_V2_TRANSPORT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-v2onlyclearnet", strprintf("Ensure all outbound IPv4/IPv6 peers use encrypted network traffic (default: %u). Using this option requires -listen=0 and takes valuable listening capacity away from the network. Enable this option only if passive network observers like ISPs, firewalls, etc. pose a threat and unencrypted network traffic must be avoided. Note: Encryption protects message contents but does not obscure that you are running a Bitcoin node. Peers can still connect to you, observers can identify Bitcoin activity from connection attempts on the default port (8333) or from analysing Bitcoin network traffic patterns.", DEFAULT_V2_ONLY_CLEARNET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
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.

Suggested change
argsman.AddArg("-v2onlyclearnet", strprintf("Ensure all outbound IPv4/IPv6 peers use encrypted network traffic (default: %u). Using this option requires -listen=0 and takes valuable listening capacity away from the network. Enable this option only if passive network observers like ISPs, firewalls, etc. pose a threat and unencrypted network traffic must be avoided. Note: Encryption protects message contents but does not obscure that you are running a Bitcoin node. Peers can still connect to you, observers can identify Bitcoin activity from connection attempts on the default port (8333) or from analysing Bitcoin network traffic patterns.", DEFAULT_V2_ONLY_CLEARNET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-v2onlyclearnet", strprintf("Ensure all outbound IPv4/IPv6 peers use encrypted network traffic (default: %u). Using this option requires -listen=0 and takes valuable listening capacity away from the network. Enable this option only if passive network observers like ISPs, firewalls, etc. pose a threat and unencrypted network traffic must be avoided. Note: Encryption protects message contents but does not obscure that you are running a Bitcoin node. Peers can still connect to you, observers can still identify Bitcoin activity from your outbound connection attempts to the default port (8333) or by analysing traffic patterns.", DEFAULT_V2_ONLY_CLEARNET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);

Comment thread src/net.cpp
std::unique_ptr<i2p::sam::Session> i2p_transient_session;

for (auto& target_addr : connect_to) {
if (RequiresV2ForOutbound(target_addr) && !use_v2transport) {
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.

If a user enables this option and wonders why connections to certain peers aren't happening, there's nothing in the debug log to explain it.

Suggested change
if (RequiresV2ForOutbound(target_addr) && !use_v2transport) {
if (RequiresV2ForOutbound(target_addr) && !use_v2transport) {
LogDebug(BCLog::NET, "skipping v1 connection to %s (-v2onlyclearnet)\n", target_addr.ToStringAddrPort());

Comment thread src/net.cpp
std::unique_ptr<i2p::sam::Session> i2p_transient_session;

for (auto& target_addr : connect_to) {
if (RequiresV2ForOutbound(target_addr) && !use_v2transport) {
Copy link
Copy Markdown
Contributor

@w0xlt w0xlt May 11, 2026

Choose a reason for hiding this comment

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

When pszDest is unresolved because DNS is delegated to a name proxy, it might be better to treat it as possibly IPv4/IPv6 and block v1 under -v2onlyclearnet.

Suggested change
if (RequiresV2ForOutbound(target_addr) && !use_v2transport) {
const bool possibly_clearnet_name{pszDest && !target_addr.IsValid()};
if ((RequiresV2ForOutbound(target_addr) ||
(m_v2only_clearnet && possibly_clearnet_name)) &&
!use_v2transport) {

P.S.: Same logic can be applied to DisconnectNodes().

                 // and we don't want to hold up the socket handler thread for that long.
-                if (network_active && !RequiresV2ForOutbound(pnode->addr) && pnode->m_transport->ShouldReconnectV1()) {
+                const bool possibly_clearnet_name{
+                    m_v2only_clearnet && !pnode->addr.IsValid() && !pnode->m_dest.empty()};
+                if (network_active && !RequiresV2ForOutbound(pnode->addr) &&
+                    !possibly_clearnet_name && pnode->m_transport->ShouldReconnectV1()) {
                     reconnections_to_add.push_back({
                         .addr_connect = pnode->addr,

@davidgumberg
Copy link
Copy Markdown
Contributor

Can you elaborate on how v2 without inbounds makes traffic analysis more difficult than v2 with inbounds? I'm not a traffic analysis expert, and to me it would make sense that any analysis happening on 10 v2 connections vs 125 v2 connections would come to the same conclusion about whether or not you were running a bitcoin node?

I think there are two issues if you don't want to be discovered that you are running a node and have listen=1 set:

  1. There are messages being passed around (on v1 connections for as long as there are v1 connections) with your address written on it that say "This address is a bitcoin node!".
  2. Any hostile network can probe that you are running a node by attempting to v2 handshake you, and honestly this is not a large escalation in threat model, this is a widely deployed technique by many passive observers. (https://dl.acm.org/doi/epdf/10.1145/2815675.2815690)

That being said, I still lean toward option B, of not tying -v2only to listen=0, even though in many cases one wants both, there are also cases that may want one without the other (you don't care about being detected as a node but you want to make it harder for a passive observer to learn anything interesting from your bitcoin traffic). Maybe in the future it would be good to have a single flag that enables sane defaults for privacy or some privacy document describing the shortcomings and tradeoffs of the available options.

I am Concept +0 leaning towards Concept ACK on this, I agree that given all of the other privacy issues that exist in both Bitcoin P2P and Bitcoin Core's implementation there won't be a step change in privacy from doing this; but I am very skeptical of this species of argument since the same arguments are used circularly to persist the other practices that degrade privacy persist, e.g. port 8333 (why change the port if we are detectable anyways via v1 connections?) Yes there are other problems, and they ought to be addressed, but raising the cost seems a good direction.

The only concern I feel hasn't been clearly addressed is the depletion of inbound v1 slots on the network; but maybe this isn't an issue needing discussing yet since so few will run with this option enabled.

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.

V2 Only Option