libtorrent icon indicating copy to clipboard operation
libtorrent copied to clipboard

Identify I2P peers

Open glassez opened this issue 1 year ago • 24 comments

Can't find a way to identify I2P peers. peer_info contains only IP and port number which are meaningless for I2P.

glassez avatar Mar 18 '23 10:03 glassez

Actually there is torrent_peer::dest() that could have a counterpart in peer_info (even better in base32 i2p name form). Unfortunately I have a feeling that @arvidn will upset us again by not being able to add some new field in peer_info, as this will break ABI compatibility.

glassez avatar Mar 19 '23 15:03 glassez

I've had same problem while trying to make deluge-torrent show i2p peers. My "solution" has been showing peer_id in place of ip:port to make some sense.

jiigen avatar Mar 21 '23 06:03 jiigen

My "solution" has been showing peer_id in place of ip:port to make some sense.

IIRC, peer_id has the same meaning for regular and i2p peers while i2p destination is more appropriate counterpart of IP:port.

glassez avatar Mar 21 '23 11:03 glassez

My "solution" has been showing peer_id in place of ip:port to make some sense.

I think that putting non-addresses into address column is inappropriate. For me it is better to have no data there at all until proper solution is developed.

Vort avatar Mar 21 '23 11:03 Vort

@glassez @Vort you're both right but as long as there's no way to get i2p destinations I thought that having an unique identifier for an i2p peer was better (just for visualizarion) than a list of empty addresses with no meaning. Biglybt as I know has an internal minimal i2p router implementation so it can retrieve destinations. I've never used it so I don't know if those are shown even when using a standalone "external" i2p router (java or i2pd). Did you tried it?

jiigen avatar Mar 22 '23 05:03 jiigen

Can't find a way to identify I2P peers. peer_info contains only IP and port number which are meaningless for I2P.

It seems that peers do not have any (common) unique identifier at all (at least accessible to the client application), so that by obtaining two consecutive peer_info sets, we could uniquely determine the peers common to both sets.

glassez avatar Mar 24 '23 04:03 glassez

After making small changes to libtorrent and adding its support to qBittorrent, I can offer the following:

i2p

glassez avatar Mar 24 '23 18:03 glassez

@glassez Seems you've found a way!

jiigen avatar Mar 25 '23 08:03 jiigen

@glassez Please take into consideration options to disable dht and pex for i2p torrents when mixed mode is not enabled (if possible) since those can't be done over i2p yet (till libtorrent doesn't implement them) and to check if the client tries to resolve the tracker's address on clearnet (it obviously fails but it's still a leak). For the rest....Great job!!

jiigen avatar Mar 25 '23 08:03 jiigen

it's true that adding a field to hold the i2p destination in peer_info would break ABI. An alternative approach would be to ensure the peer-id is unique (or maybe even contain the first part of the destination).

I imagine that the actual destination isn't really important. I would expect all of them to be ephemeral keys set up just for this connection. If you disconnect and reconnect to the same peer later, it may have a different destination address.

Are those destination addresses base32? (it looks like the .b32 part of the address might indicate that). Does that mean they are 32 byte keys? If so, the current fields ip and local_endpoint could be turned into a union holding those 32 bytes of key, when the peer is an i2p peer.

arvidn avatar Mar 25 '23 16:03 arvidn

Are those destination addresses base32? (it looks like the .b32 part of the address might indicate that). Does that mean they are 32 byte keys?

"I2P uses 52 characters (256 bits) to represent the full SHA-256 hash. The form is {52 chars}.b32.i2p." https://geti2p.net/en/docs/naming#base32

Vort avatar Mar 25 '23 16:03 Vort

Are those destination addresses base32? (it looks like the .b32 part of the address might indicate that). Does that mean they are 32 byte keys?

"I2P uses 52 characters (256 bits) to represent the full SHA-256 hash. The form is {52 chars}.b32.i2p." https://geti2p.net/en/docs/naming#base32

I2P destination is base64 encoded fingerprint of peer. Base32 I2P address is base32encode(sha256(base64decode(destination))) with removed trailing pad characters, converted to lower case and appended with .b32.i2p.

glassez avatar Mar 25 '23 17:03 glassez

Actually there are two kind of issues: unique identification of peers within current set in general, and (possibly as a subproblem), the lack of providing analog of IP addresses for I2P peers.

it's true that adding a field to hold the i2p destination in peer_info would break ABI. An alternative approach would be to ensure the peer-id is unique (or maybe even contain the first part of the destination).

IIRC, peer_id just provides corresponding field reported by peers to tracker. So many people expect to have exactly this data there in order to use it in the traditional way. The problem is that many peers have it empty at all (at least that's how it looks when I get a peer_info's from libtorrent). So we can't use it as unique identifier.

I imagine that the actual destination isn't really important. I would expect all of them to be ephemeral keys set up just for this connection. If you disconnect and reconnect to the same peer later, it may have a different destination address.

It would still be useful for the purposes of visual distinguishing the currently displayed peers.

glassez avatar Mar 25 '23 17:03 glassez

Does that mean they are 32 byte keys? If so, the current fields ip and local_endpoint could be turned into a union holding those 32 bytes of key, when the peer is an i2p peer.

32 byte is enough to provide address in intermediate sha256 encoded form. Although I feel it as a workaround, we can still use it until next update.

IMO, the main things that we should take out of the discussion of problems like this is the changes that should be added to the master (since we can't add them to the release branches), and how to modify the API of the master so that in the future we have fewer such problems with ABI compatibility.

glassez avatar Mar 25 '23 17:03 glassez

Base32 I2P address is base32encode(sha256(base64decode(destination))) with removed trailing pad characters, converted to lower case and appended with .b32.i2p.

So, exposing the SHA-256 hashes for peers, that would be a reasonable, long-term format for the API, right?

looking over this code, it would be really nice to switch to using this format for i2p destinations internally too, to avoid string handling and heap allocations.

arvidn avatar Mar 25 '23 20:03 arvidn

Not sure what place are you talking about, but full base64 keys are needed for interactions with SAM.

Vort avatar Mar 25 '23 21:03 Vort

Not sure what place are you talking about, but full base64 keys are needed for interactions with SAM.

That's not what the documentation says (here):

NOTE: Since about 2014 (SAM v3.1), Java I2P has also supported hostnames and b32 addresses for the $destination, but this was previously undocumented. Hostnames and b32 addresses are now officially supported by Java I2P as of release 0.9.48

I also find it quite confusing to refer to the kind of destination address by what encoding it's using, as if that was the main distinction. The "base32" addresses are just the sha256 hash of a destination, and a destination is the full key (afaiu).

The former is usually encoded with base32 and the latter is usually encoded with base64.

arvidn avatar Mar 25 '23 21:03 arvidn

That's not what the documentation says

STREAM ACCEPT uses full key: "SAM bridge sends the client a ASCII line containing the base64 public destination key of the requesting peer" https://geti2p.net/en/docs/api/samv3

Vort avatar Mar 25 '23 21:03 Vort

I don't understand what point you're making. My reading of the document I linked to allows me to SHA-256 that base64 encoded destination string and use that hash to refer to that peer. If I want to connect back to it, I just base32 encode the hash and append .b32.i2p and I'm good to go.

arvidn avatar Mar 25 '23 21:03 arvidn

Ok, I agree that it may be possible. However I'm not sure which approach will be faster.

  1. Frequent "string handling and heap allocations" vs occasional SHA256.
  2. Making base32 -> base64 lookups manually vs allowing i2p software to make them instead.

Vort avatar Mar 25 '23 22:03 Vort

I asked @orignal and he said that storing of base32 addresses is good solution.

Vort avatar Mar 25 '23 22:03 Vort

There is undocumented hack that both i2pd and Java I2p allows .i2p addresses in STREAM CONNECT directly, including .b32.i2p

In i2pd if (destination.find(".i2p") != std::string::npos) addr = context.GetAddressBook().GetAddress (destination);

So you don't need full base64 address to connect to a destination. b32 address in enough to store.

It also works with B33 addresses(encrypted LeaseSet) where full base64 address doesn't exist.

orignal avatar Mar 25 '23 22:03 orignal

@orignal it's even documented and officially supported by now (as I quoted here).

@glassez how does this look? https://github.com/arvidn/libtorrent/pull/7356 There are a few other commits in there to fix up i2p support, but the main commit is adding lt::sha256_hash peer_info::i2p_destination().

arvidn avatar Mar 26 '23 09:03 arvidn

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Aug 12 '23 18:08 stale[bot]