-
Notifications
You must be signed in to change notification settings - Fork 38.7k
p2p: Ignore ports on I2P addresses #21514
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. 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. |
|
Concept ACK I think it would be a useful abstraction to introduce |
5c3eaea to
f30e489
Compare
|
"uses ports or not" is a per-network property (like IPv4 uses ports, I2P does not use ports), so I added a standalone function that takes an |
|
Thanks for working on this! Will review soon. |
jonatack
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.
ACK f30e489c3882cd58e382c203e5e4722fbe70f58e with some suggestions
src/test/netbase_tests.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.
987d372 Verified that these new assertions fail without the change to ToStringIPPort() in the same commit.
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.
While here, maybe sneak this minor fixup into the commit
-bool static TestParse(std::string src, std::string canon)
+bool static TestParse(const std::string& src, const std::string& canon)
{
- CService addr(LookupNumeric(src, 65535));
+ CService addr{LookupNumeric(src, 65535)};
src/test/netbase_tests.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.
8f4bd325 This I2P address string is created 4 times in this test file now; perhaps hoist to a constant.
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 prefer to keep it local to each test. It is just a random address, does not need to be equal in all test cases.
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.
6f19e34 suggested simplification
def test_addnode_and_connect_i2p(self):
- self.log.info('Test that ports are removed from -addnode= and -connect= I2P addresses')
-
+ self.log.info("Test ports are removed from I2P addresses passed to -addnode/-connect")
i2p_addr = "ukeu3k5oycgaauneqgtnvselmt4yemvoilkln7jpvamvfx7dnkdq.b32.i2p"
i2p_addr_with_port = i2p_addr + ":3333"
-
- self.stop_node(0)
- with self.nodes[0].assert_debug_log(expected_msgs=[
- f"trying connection {i2p_addr} lastseen=",
- ]):
- self.start_node(0, extra_args=[f"-addnode={i2p_addr_with_port}"])
-
- self.stop_node(0)
- with self.nodes[0].assert_debug_log(expected_msgs=[
- f"trying connection {i2p_addr} lastseen=",
- ]):
- self.start_node(0, extra_args=[f"-connect={i2p_addr_with_port}"])
+ msg = [f"trying connection {i2p_addr} lastseen="]
+ for option in {"addnode", "connect"}:
+ with self.nodes[0].assert_debug_log(expected_msgs=msg):
+ self.restart_node(0, extra_args=[f"-{option}={i2p_addr_with_port}"])
def run_test(self):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.
Taketh, thanks!
One minor downside of the new variant is that if we get exception on line 224, then it is not clear whether the problem is in -addnode or -connect.
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.
Good point, loglevel=debug (logged by the CI in case of failure) would reliably indicate which one if we use an array/dict rather than a set:
- for option in {"addnode", "connect"}:
+ for option in ["addnode", "connect"]:or by adding, for instance
for option in {"addnode", "connect"}:
+ self.log.debug(f"-{option}")
with self.nodes[0].assert_debug_log(expected_msgs=[msg]):then the log would show
2021-04-01T17:42:16.846000Z TestFramework (INFO): Test ports are removed from I2P addresses passed to -addnode/-connect
2021-04-01T17:42:16.846000Z TestFramework (DEBUG): -connect
2021-04-01T17:42:16.846000Z TestFramework.node0 (DEBUG): Stopping node
2021-04-01T17:42:16.999000Z TestFramework.node0 (DEBUG): Node stopped
2021-04-01T17:42:17.002000Z TestFramework.node0 (DEBUG): bitcoind started, waiting for RPC to come up
2021-04-01T17:42:17.512000Z TestFramework.node0 (DEBUG): RPC successfully started
2021-04-01T17:42:17.514000Z TestFramework (DEBUG): -addnode
2021-04-01T17:42:17.514000Z TestFramework.node0 (DEBUG): Stopping node
2021-04-01T17:42:17.618000Z TestFramework.node0 (DEBUG): Node stopped
2021-04-01T17:42:17.628000Z TestFramework.node0 (DEBUG): bitcoind started, waiting for RPC to come up
2021-04-01T17:42:18.140000Z TestFramework.node0 (DEBUG): RPC successfully started
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.
...would reliably indicate which one if we use an array/dict rather than a set...
Hmm, I tried this, but did not see any difference in the output, what am I missing? (I sneaked a deliberate change of the expected message if the option is e.g. addnode in order to trigger a failure).
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 wasn't very clear. I meant that it would have a fixed order so you would know which failure it is. Array + debug logging probably best.
|
|
f30e489 to
5be0a46
Compare
|
re-ACK 5be0a46b1623536d98aec641af0d24401995e837 |
|
Would it make sense to make it illegal for I2P hostnames to have a port in the first place? |
We receive I2P host names from the outside world from:
The first two receive string arguments, so we can parse them and reject/return an error if we see an I2P address followed by On the P2P layer we inevitably receive a port in the addrv2 encoding. We may insist that the port is e.g. I2P in general supports ports. It is just the proxy protocol we use that does not support them (SAM 3.1). Other proxy protocols or newer versions of SAM do support ports (we don't use newer SAM versions because So, I think it is best to ignore ports in I2P addresses and some day in the distant future if we decide to support them, then revert parts of this PR. But not impose restrictions on the P2P protocol. |
|
Hmm can you explain a bit more what changes in later SAM protocols? The ability to create "portful" services, the ability to connect to them, both, ... what happens when an older-protocol node tries to connect to portful newer-protocol node or the other way around? This may inform what to do, if we envision ever adopting a later version. |
|
If helpful,
|
|
@sipa, short answer - it works either way. Long answer:
Both. The SAM protocol is described here: https://geti2p.net/en/docs/api/samv3 (relevant: "Version 3.2 Changes" and "FROM_PORT" / "TO_PORT").
raw transcripts in case somebody wants to play |
|
@vasild So... that kind of calls for treating the lack of ports right now as forcing port=0. I guess that's a bit annoying to implement, but if it's possible perhaps the most forward-compatible approach:
That would mean that if/when ports are actually adopted, you won't get any surprises. |
5be0a46 to
9ea6503
Compare
|
|
|
@sipa, I made some further experiments. Since one may connect to I2P in ways other than using the SAM protocol, I tried using the I2P router's HTTP proxy to connect to a SAM 3.2 listener (who has done
Hmm... |
|
So, it looks like with I2P we listen on just |
|
Concept ACK on improving abstractions. |
|
re-ACK 9ea6503d753a3c84bc2ea3b3e61504e8bd46c40c modulo ensuring this change is compatible with the I2P seeds and non-default port check in net.cpp::CConnman::ThreadOpenConnections. (When testing the I2P seed nodes for #21825, I first tried adding them with no port numbers. Testing with a fresh peers.dat and only those I2P seeds in chainparamsseeds and in my AddrMan, I realizing they weren't organically connecting because the port number was missing (e.g. a missing port is converted to 0). Adding port 8333 like for the other seeds enabled the I2P ones to connect immediately.) |
|
Would be good to have this fixed for v22. |
From our perspective ports are ignored when connecting to the I2P network. I.e. `aaa.b32.i2p:1111` is the same as `aaa.b32.i2p:2222`, so compare them equal to avoid redundant connections to the same node if ports happen to differ for some reason. Fixes bitcoin#21389
Since ports are irrelevant in our usage of I2P, print just `aaa.b32.i2p` instead of `aaa.b32.i2p:8333` when converting `CService` to string.
This makes printing to the log proper (without ports for I2P addresses).
This makes printing to the log proper (without ports for I2P addresses) and also discovers duplicates earlier in `CConnman::AddNode()`.
For networks that do not use ports (e.g. I2P), remove the `:port` suffix (if any) when searching for an address by string.
This is a followup to `236618061a445d2cb11e722cfac5fdae5be26abb` which forgot to update the comment - we don't return the existent connection from `CConnman::ConnectNode()` anymore after that commit.
9ea6503 to
6d8d592
Compare
|
|
4101ec9 doc: mention that we enforce port=0 in I2P (Vasil Dimov) e0a2b39 addrman: reset I2P ports to 0 when loading from disk (Vasil Dimov) 41cda9d test: ensure I2P ports are handled as expected (Vasil Dimov) 4f432bd net: do not connect to I2P hosts on port!=0 (Vasil Dimov) 1f096f0 net: distinguish default port per network (Vasil Dimov) aeac3bc net: change I2P seeds' ports to 0 (Vasil Dimov) 38f9002 net: change assumed I2P port to 0 (Vasil Dimov) Pull request description: _This is an alternative to bitcoin/bitcoin#21514, inspired by bitcoin/bitcoin#21514 (comment). They are mutually exclusive. Just one of them should be merged._ Change assumed ports for I2P to 0 (instead of the default 8333) as this is closer to what actually happens underneath with SAM 3.1 (bitcoin/bitcoin#21514 (comment), bitcoin/bitcoin#21514 (comment)). Don't connect to I2P peers with advertised port != 0 (we don't specify a port to our SAM 3.1 proxy and it always connects to port = 0). Note, this change: * Keeps I2P addresses with port != 0 in addrman and relays them to others via P2P gossip. There may be non-bitcoin-core-22.0 peers using SAM 3.2 and for them such addresses may be useful. * Silently refuses to connect to I2P hosts with port != 0. This is ok for automatically chosen peers from addrman. Not so ok for peers provided via `-addnode` or `-connect` - a user who specifies `foo.b32.i2p:1234` (non zero port) may wonder why "nothing is happening". Fixes #21389 ACKs for top commit: laanwj: Code review ACK 4101ec9 jonatack: re-ACK 4101ec9 per `git range-diff efff9c3 0b0ee03 4101ec9`, built with DDEBUG_ADDRMAN, did fairly extensive testing on mainnet both with and without a peers.dat / -dnsseeds=0 to test boostrapping. Tree-SHA512: 0e3c019e1dc05e54f559275859d3450e0c735596d179e30b66811aad9d5b5fabe3dcc44571e8f7b99f9fe16453eee393d6e153454dd873b9ff14907d4e6354fe
|
Closing in favor of #22112 (which was merged). |
This is an alternative to #22112. They are mutually exclusive. Just one of them should be merged.
Background
Listening for incoming connections in I2P does not involve a port - we just listen on an address. Similarly we just connect to an I2P address, without a port (this is in I2P SAM 3.1, what's used in Bitcoin Core).
Problem
It is possible to connect to the same node multiple times if different ports are used.
Solution
For I2P addresses:
CServiceobjectsCService::ToString()CConnMan::FindNode(std::string)) and to print without the ports in the cases where we print the user input without converting it toCServiceobject and using itsToString()methodFixes #21389