Skip to content
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

About holepunching test #857

Open
nj1220 opened this issue Aug 10, 2023 · 5 comments
Open

About holepunching test #857

nj1220 opened this issue Aug 10, 2023 · 5 comments

Comments

@nj1220
Copy link

nj1220 commented Aug 10, 2023

I'm interested in the holepunching test (torrent/ut-holepunching_test.go).

In the test, Seeder and Leecher-Leecher realized the hole punching function with the help of Leecher. I would like to ask if I need to configure the role of Leecher in the actual use scenario?

I want to realize a scenario: start two nodes (client) behind different NAT devices respectively, and then the two nodes realize connecting directly. How to use the interface provided in anacrolix/torrent to realize it? (Looks like anacrolix/torrent doesn't expose an explicit interface to provide direct connection functionality)

@anacrolix
Copy link
Owner

The two peers will need a mutual peer that they can both connect to. This is difficult to achieve predictably in the wild, but you could run your own "leecher" in this role if it was not behind a NAT, or more specifically, both the other peers can and do connect to it before trying to connect to each other. Such a test would be very valuable.

@nj1220
Copy link
Author

nj1220 commented Aug 13, 2023

Thank you for your prompt reply!! I still have some questions:

Is it possible to choose some public nodes in the Bittorrent network as mutual peer? Similar to "router.utorrent.com:6881", "dht.transmissionbt.com:6881", or "dht.anacrolix.link:42069" provided by anacrolix. Also, does anacrolia/torrent provide relevant configuration items to achieve common peers for configuration disclosure to assist hole punching?

I raised the above question because: in my demo, peerA and peerB are located in different intranets (behind different NAT devices), peerA publishes a resource (infohash), and peerB finds the addr of peerA through get_peers, but cannot directly establish a connection.

I also have no conditions to run a leecher under the public network IP. p.s. I think most p2p nodes are like this.

@anacrolix
Copy link
Owner

Is it possible to choose some public nodes in the Bittorrent network as mutual peer? Similar to "router.utorrent.com:6881", "dht.transmissionbt.com:6881", or "dht.anacrolix.link:42069" provided by anacrolix. Also, does anacrolia/torrent provide relevant configuration items to achieve common peers for configuration disclosure to assist hole punching?

No, unfortunately the BitTorrent holepunching operates over the BitTorrent protocol, not over the DHT. See https://www.bittorrent.org/beps/bep_0055.html. This means you can only connect to peers through relays that are in the same swarm (share the same infohash). Using the DHT would make much more sense, I don't know why it doesn't operate like this.

anacrolix/torrent.Client does provide port forwarding by default, which may work depending on your network setup. See ClientConfig.NoDefaultPortForwarding. The implementation used is https://github.com/anacrolix/upnp.

I raised the above question because: in my demo, peerA and peerB are located in different intranets (behind different NAT devices), peerA publishes a resource (infohash), and peerB finds the addr of peerA through get_peers, but cannot directly establish a connection.

It is fairly common, however it does only take a single peer, to facilitate connections. Most peers (60-70%?) are also able to work around NAT with some form of port forwarding.

I also have no conditions to run a leecher under the public network IP. p.s. I think most p2p nodes are like this.

To avoid confusion, I should correct the terminology here, I think you mean a "relaying" peer. The seeder/leecher/leecher leecher naming I use in the test are inherited from some other tests. In the tests, the leecher acts as the relaying peer, since the other two peers are only connected to it.

@nj1220
Copy link
Author

nj1220 commented Aug 17, 2023

According to the https://www.bittorrent.org/beps/bep_0055.html, it said "The initiating peer sends a rendezvous message to the relaying peer, containing the endpoint (IP address and port) of the target peer. If the relaying peer is connected to the target peer, and the target peer supports this extension, the relaying peer sends a connect message to both the initiating peer and the target peer, each containing the endpoint of the other. Upon receiving the connect message, each peer initiates a uTP connection to the other peer."

I agree with the above functional flow of the hole punching protocol. However, for direct connection through NAT traversal between two nodes located behind NAT devices, the relay peer needs to control the time point when they are connected to each other while sending connection messages to the initiating peer and the target peer. In this way, they initiate a connection with each other almost "simultaneously" to complete most NAT traversal except symmetric NAT (Because the symmetric NAT device randomly assigns ports, so this way doesn't work).

In torrent/torrent.go (func (t *Torrent) handleReceivedUtHolepunchMsg), I only see the relay peer sending connection messages to the initiating peer and the target peer, and i don't see any measures to control the time point. so this leads to, in torrent/ut-holepunching_test.go, leecher-leecher can only initiate a connection with the seeder after the seeder actively establishes a connection with it, and this also relies on leecher-leecher accepting any inbound connections. I guess this doesn't quite meet the full functional requirements of the regular holepunching protocol. Is it possible to improve on this?

@anacrolix
Copy link
Owner

I agree with the above functional flow of the hole punching protocol. However, for direct connection through NAT traversal between two nodes located behind NAT devices, the relay peer needs to control the time point when they are connected to each other while sending connection messages to the initiating peer and the target peer. In this way, they initiate a connection with each other almost "simultaneously" to complete most NAT traversal except symmetric NAT (Because the symmetric NAT device randomly assigns ports, so this way doesn't work).

I'm not sure this is true. There should be no regular set up where it's possible for one peer's attempt to connect to arrive at the other peer before that peer has initiated it's own connection attempt. If a NAT is a negligible distance from its respective peer it may be possible, but this would occur independent of any attempt to fudge the timing on the part of the relaying peer. I know the IPFS guys did some research in this area and introduced an attempt to time things, but it's my impression this would only give very marginal gains. Please feel free to construct a counter example that demonstrates I have this wrong. I also don't believe I saw anything about timing mentioned in the BEP, and I'm not aware of any BitTorrent client that does it either.

in torrent/ut-holepunching_test.go, leecher-leecher can only initiate a connection with the seeder after the seeder actively establishes a connection with it, and this also relies on leecher-leecher accepting any inbound connections. I guess this doesn't quite meet the full functional requirements of the regular holepunching protocol. Is it possible to improve on this?

Yeah it's not a complete test. I artificially prevent seeder from accepting connections and then tell leecher-leecher to try to connect to it. This forces it to use the relay (leecher), which tells seeder to connect to leecher leecher directly. I'm really only testing the signalling here. I would need to introduce an artificial NAT, or mock out the connections to control when they can connect or not. It is doable (particularly the latter approach), but I only spent so much time on this. I am definitely open to a more complete test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants