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

Add announce_port support #7771

Merged
merged 1 commit into from
Nov 9, 2024
Merged

Add announce_port support #7771

merged 1 commit into from
Nov 9, 2024

Conversation

0xThiebaut
Copy link
Contributor

@0xThiebaut 0xThiebaut commented Oct 26, 2024

The announce_port setting permits to overwrite the port passed along to trackers as the &port= parameter. If left as the default, the listening port is used. This setting is only meant for very special cases where a seed's listening port differs from the effectively exposed port (e.g., through external NAT-PMP).

This PR would be complementary to the #7726 listen_on_proxy setting.

@0xThiebaut
Copy link
Contributor Author

0xThiebaut commented Oct 26, 2024

Example use-case

To secure outbound connections, a proxy server on the same subnet can be used to tunnel requests through a VPN (e.g., using pufferffish/wireproxy). Some VPNs support NAT-PMP (e.g., ProtonVPN) which could technically allow the proxy server to perform dynamic port forwarding back.

Through the announce_port setting, a tracker can be informed which NAT-PMP port has been made available through the proxy while the proxy has been configured to direct requests from the announced port to the actual listening port.

Announce Port

Copy link
Owner

@arvidn arvidn left a comment

Choose a reason for hiding this comment

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

I think it would be good to have some test coverage of this feature. Maybe you could add a test case here:

https://github.com/arvidn/libtorrent/blob/RC_2_0/simulation/test_tracker.cpp#L384-L410

src/http_tracker_connection.cpp Outdated Show resolved Hide resolved
src/tracker_manager.cpp Outdated Show resolved Hide resolved
include/libtorrent/settings_pack.hpp Outdated Show resolved Hide resolved
@0xThiebaut 0xThiebaut force-pushed the announce_port branch 3 times, most recently from 27501ad to adea10c Compare October 27, 2024 16:06
@0xThiebaut
Copy link
Contributor Author

I think it would be good to have some test coverage of this feature. Maybe you could add a test case here:

https://github.com/arvidn/libtorrent/blob/RC_2_0/simulation/test_tracker.cpp#L384-L410

A simple test coverage has been added to ensure announce_ip and announce_port are properly reflected in the tracker URL.

Copy link
Owner

@arvidn arvidn left a comment

Choose a reason for hiding this comment

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

looks good. would you mind adding a line to Changelog too?

@0xThiebaut 0xThiebaut force-pushed the announce_port branch 2 times, most recently from b7398b9 to 798ead8 Compare October 27, 2024 19:05
@0xThiebaut
Copy link
Contributor Author

looks good. would you mind adding a line to Changelog too?

Done as well, thanks!

@arvidn
Copy link
Owner

arvidn commented Oct 28, 2024

should this feature affect the port we announce to the DHT?
the current default is to use "implied port", i.e. the source port of the DHT message. This works since we accept uTP connections on the same port.

@arvidn
Copy link
Owner

arvidn commented Oct 28, 2024

and I imagine it should not affect local service discovery announcements (i.e. multicast on the local network)

@0xThiebaut
Copy link
Contributor Author

The announce_port feature is intended for cases where additional appliances are located between local and remote peers. The local network discovery is by definition local so I agree it should not be affected by the announce_port setting. A future boolean setting could be introduced should anyone manage to find a use-case requiring announce_port overrides for local network discovery.

For DHT/uTP there can however be appliances between the local and remote peers; It would make sense to support overriding the announced port. I'm not familiar with DHT/uTP, do they currently use the same listening port as the TCP listener but for UDP?

@arvidn
Copy link
Owner

arvidn commented Oct 28, 2024

I'm not familiar with DHT/uTP, do they currently use the same listening port as the TCP listener but for UDP?

Yes, libtorrent attempts to open the listen socket for TCP and UDP on the same port. The UDP socket is used for DHT, uTP (peer connections) and UDP trackers.

@0xThiebaut
Copy link
Contributor Author

My current understanding would be as follow:

For UDP trackers I think we are covered as it uses req.listen_port which announce_port overrides.

aux::write_uint16(req.listen_port, out); // port

For uTP (peer connections) I don't believe there is a notion of "announcing"; it is merely the transport protocol and does not define which ports are used.

For DHT we need to ensure that announce_port indeed overrides the announced port. I believe we would need to do so in the session implementation and, if announce_port is set, make sure to clear the dht::announce::implied_port flag while overriding the port argument.

void session_impl::dht_announce(sha1_hash const& info_hash, int port, dht::announce_flags_t const flags)
{
if (!m_dht) return;
m_dht->announce(info_hash, port, flags, std::bind(&on_dht_get_peers, std::ref(m_alerts), info_hash, _1));
}

Would that make sense?

@0xThiebaut
Copy link
Contributor Author

Another DHT option is to do it at node-level where the logic already replaces 0 with the listening port; Although doing it at session-level would match the TCP announce_port variant.

if (listen_port == 0 && m_observer != nullptr)
{
listen_port = m_observer->get_listen_port(
(flags & announce::ssl_torrent) ? aux::transport::ssl : aux::transport::plaintext
, m_sock);
}
get_peers(info_hash, std::move(f)
, std::bind(&announce_fun, _1, std::ref(*this)
, listen_port, info_hash, flags), flags);

@arvidn
Copy link
Owner

arvidn commented Oct 29, 2024

I can land this PR, and if you think the DHT behavior also should change, you could make another PR. I think having this logic in the session would make sense. It might also make sense to update the documentation for the setting to make it clear that it doesn't affect local service discovery and whether or not it affects DHT announces

@0xThiebaut
Copy link
Contributor Author

I'll update the PR today to reflect that announce_port does not affect local discovery. I'll also apply the DHT change as I would rather avoid complex documentation with non-intuitive edge-cases.

@0xThiebaut
Copy link
Contributor Author

I might be misunderstanding the relationship between a session and a torrent but wouldn't the following bypass the announce_port applied in the session's session_impl::dht_announce? Based on my limited understanding I would have expected the torrent to call m_ses.dht_announce() instead of m_ses.dht()->announce().

libtorrent/src/torrent.cpp

Lines 2816 to 2820 in e5fe95f

m_torrent_file->info_hashes().for_each([&](sha1_hash const& ih, protocol_version v)
{
m_ses.dht()->announce(ih, 0, flags
, std::bind(&torrent::on_dht_announce_response_disp, self, v, _1));
});

@arvidn
Copy link
Owner

arvidn commented Oct 29, 2024

there's only one DHT node (technically, one per network interface you have). And to smooth-out the network traffic, torrents announces are staggered. The session loops over all the torrents and announces them one at a time, at a pace making them all announce once per 15 minutes (or whatever the setting has been set to).

@0xThiebaut
Copy link
Contributor Author

So on top of applying announce_port in session_impl::dht_announce we also need to add it to torrent::dht_announce as both functions determine a port to use? Or we move the logic to the underlying dht_tracker::announce which is used by both the session_impl and torrent?

Apologies if I am missing something.

src/session_impl.cpp Outdated Show resolved Hide resolved
ChangeLog Outdated Show resolved Hide resolved
@arvidn
Copy link
Owner

arvidn commented Nov 1, 2024

thanks for your patience. I just did one more review pass

@arvidn arvidn merged commit f9dde82 into arvidn:RC_2_0 Nov 9, 2024
42 checks passed
@arvidn
Copy link
Owner

arvidn commented Nov 9, 2024

thanks!

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

Successfully merging this pull request may close these issues.

2 participants