Skip to content

Commit f9dde82

Browse files
0xThiebautarvidn
authored andcommitted
Add announce_port support
1 parent 7f69124 commit f9dde82

File tree

7 files changed

+113
-8
lines changed

7 files changed

+113
-8
lines changed

ChangeLog

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* fix integer overflow in piece picker
1616
* torrent_status::num_pieces counts pieces passed hash check, as documented
1717
* check settings_pack::max_out_request_queue before performance alert
18+
* add announce_port setting to override the port announced to trackers
1819

1920
2.0.10 released
2021

include/libtorrent/session_handle.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ namespace libtorrent {
507507
// specified info-hash, advertising the specified port. If the port is
508508
// left at its default, 0, the port will be implied by the DHT message's
509509
// source port (which may improve connectivity through a NAT).
510+
// ``dht_announce()`` is not affected by the ``announce_port`` override setting.
510511
//
511512
// Both these functions are exposed for advanced custom use of the DHT.
512513
// All torrents eligible to be announce to the DHT will be automatically,

include/libtorrent/settings_pack.hpp

+14
Original file line numberDiff line numberDiff line change
@@ -2068,6 +2068,20 @@ namespace aux {
20682068
i2p_inbound_length,
20692069
i2p_outbound_length,
20702070

2071+
// ``announce_port`` is the port passed along as the ``port`` parameter
2072+
// to remote trackers such as HTTP or DHT. This setting does not affect
2073+
// the effective listening port nor local service discovery announcements.
2074+
// If left as zero (default), the listening port value is used.
2075+
//
2076+
// .. note::
2077+
// This setting is only meant for very special cases where a
2078+
// seed's listening port differs from the external port. As an
2079+
// example, if a local proxy is used and that the proxy supports
2080+
// reverse tunnels through NAT-PMP, the tracker must connect to
2081+
// the external NAT-PMP port (configured using ``announce_port``)
2082+
// instead of the actual local listening port.
2083+
announce_port,
2084+
20712085
max_int_setting_internal
20722086
};
20732087

simulation/test_tracker.cpp

+84
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,90 @@ void on_alert_notify(lt::session* ses)
361361
});
362362
}
363363

364+
void test_announce()
365+
{
366+
using sim::asio::ip::address_v4;
367+
sim::default_config network_cfg;
368+
sim::simulation sim{network_cfg};
369+
370+
sim::asio::io_context web_server(sim, make_address_v4("2.2.2.2"));
371+
372+
// listen on port 8080
373+
sim::http_server http(web_server, 8080);
374+
375+
int announces = 0;
376+
377+
// expect announced IP & port
378+
std::string const expect_port = "&port=1234";
379+
std::string const expect_ip = "&ip=1.2.3.4";
380+
381+
http.register_handler("/announce"
382+
, [&announces, expect_port, expect_ip](std::string method, std::string req
383+
, std::map<std::string, std::string>&)
384+
{
385+
++announces;
386+
TEST_EQUAL(method, "GET");
387+
TEST_CHECK(req.find(expect_port) != std::string::npos);
388+
TEST_CHECK(req.find(expect_ip) != std::string::npos);
389+
char response[500];
390+
int const size = std::snprintf(response, sizeof(response), "d8:intervali1800e5:peers0:e");
391+
return sim::send_response(200, "OK", size) + response;
392+
});
393+
394+
{
395+
lt::session_proxy zombie;
396+
397+
std::vector<asio::ip::address> ips;
398+
ips.push_back(make_address("123.0.0.3"));
399+
400+
asio::io_context ios(sim, ips);
401+
lt::settings_pack sett = settings();
402+
sett.set_str(settings_pack::listen_interfaces, "0.0.0.0:6881");
403+
sett.set_str(settings_pack::announce_ip, "1.2.3.4");
404+
sett.set_int(settings_pack::announce_port, 1234);
405+
406+
auto ses = std::make_unique<lt::session>(sett, ios);
407+
408+
ses->set_alert_notify(std::bind(&on_alert_notify, ses.get()));
409+
410+
lt::add_torrent_params p;
411+
p.name = "test-torrent";
412+
p.save_path = ".";
413+
p.info_hashes.v1.assign("abababababababababab");
414+
415+
p.trackers.push_back("http://2.2.2.2:8080/announce");
416+
ses->async_add_torrent(p);
417+
418+
// stop the torrent 5 seconds in
419+
sim::timer t1(sim, lt::seconds(5)
420+
, [&ses](boost::system::error_code const&)
421+
{
422+
std::vector<lt::torrent_handle> torrents = ses->get_torrents();
423+
for (auto const& t : torrents)
424+
{
425+
t.pause();
426+
}
427+
});
428+
429+
// then shut down 10 seconds in
430+
sim::timer t2(sim, lt::seconds(10)
431+
, [&ses,&zombie](boost::system::error_code const&)
432+
{
433+
zombie = ses->abort();
434+
ses.reset();
435+
});
436+
437+
sim.run();
438+
}
439+
440+
TEST_EQUAL(announces, 2);
441+
}
442+
443+
// this test makes sure that a seed can overwrite its announced IP & port
444+
TORRENT_TEST(announce_ip_port) {
445+
test_announce();
446+
}
447+
364448
static const int num_interfaces = 3;
365449

366450
void test_ipv6_support(char const* listen_interfaces

src/session_impl.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -1301,9 +1301,11 @@ namespace {
13011301
#endif
13021302
req.ssl_ctx = &m_ssl_ctx;
13031303
#endif
1304-
1305-
auto ls = req.outgoing_socket.get();
1306-
if (ls)
1304+
if (const auto announce_port = std::uint16_t(m_settings.get_int(settings_pack::announce_port)))
1305+
{
1306+
req.listen_port = announce_port;
1307+
}
1308+
else if (auto ls = req.outgoing_socket.get())
13071309
{
13081310
req.listen_port =
13091311
#ifdef TORRENT_SSL_PEERS

src/settings_pack.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,8 @@ constexpr int DISK_WRITE_MODE = settings_pack::enable_os_cache;
401401
SET(i2p_inbound_quantity, 3, nullptr),
402402
SET(i2p_outbound_quantity, 3, nullptr),
403403
SET(i2p_inbound_length, 3, nullptr),
404-
SET(i2p_outbound_length, 3, nullptr)
404+
SET(i2p_outbound_length, 3, nullptr),
405+
SET(announce_port, 0, nullptr)
405406
}});
406407

407408
#undef SET

src/torrent.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -2807,23 +2807,25 @@ bool is_downloading_state(int const st)
28072807
// If this is an SSL torrent the announce needs to specify an SSL
28082808
// listen port. DHT nodes only operate on non-SSL ports so SSL
28092809
// torrents cannot use implied_port.
2810-
// if we allow incoming uTP connections, set the implied_port
2811-
// argument in the announce, this will make the DHT node use
2810+
// if we allow incoming uTP connections and don't overwrite
2811+
// the announced port, set the implied_port argument
2812+
// in the announce, this will make the DHT node use
28122813
// our source port in the packet as our listen port, which is
28132814
// likely more accurate when behind a NAT
2815+
const auto announce_port = std::uint16_t(settings().get_int(settings_pack::announce_port));
28142816
if (is_ssl_torrent())
28152817
{
28162818
flags |= dht::announce::ssl_torrent;
28172819
}
2818-
else if (settings().get_bool(settings_pack::enable_incoming_utp))
2820+
else if (!announce_port && settings().get_bool(settings_pack::enable_incoming_utp))
28192821
{
28202822
flags |= dht::announce::implied_port;
28212823
}
28222824

28232825
std::weak_ptr<torrent> self(shared_from_this());
28242826
m_torrent_file->info_hashes().for_each([&](sha1_hash const& ih, protocol_version v)
28252827
{
2826-
m_ses.dht()->announce(ih, 0, flags
2828+
m_ses.dht()->announce(ih, announce_port, flags
28272829
, std::bind(&torrent::on_dht_announce_response_disp, self, v, _1));
28282830
});
28292831
}

0 commit comments

Comments
 (0)