generate random keys for use in tracker announces. keys are unique for each torrent and the listen interface they announce via

This commit is contained in:
arvidn 2017-11-25 16:37:47 +01:00 committed by Arvid Norberg
parent f2681412e7
commit a6656aeb93
6 changed files with 82 additions and 21 deletions

View File

@ -1,3 +1,4 @@
* make tracker keys multi-homed. remove set_key() function on session.
* add API to query whether alerts have been dropped or not
* add flags()/set_flags()/unset_flags() to torrent_handle, deprecate individual functions
* added alert for block being sent to the send buffer

View File

@ -198,6 +198,10 @@ namespace aux {
// which alias the listen_socket_t shared_ptr
std::shared_ptr<tcp::acceptor> sock;
std::shared_ptr<aux::session_udp_socket> udp_sock;
// the key is an id that is used to identify the
// client with the tracker only.
std::uint32_t tracker_key = 0;
};
struct TORRENT_EXTRA_EXPORT listen_endpoint_t
@ -583,6 +587,8 @@ namespace aux {
std::uint16_t ssl_listen_port() const override;
std::uint16_t ssl_listen_port(listen_socket_t* sock) const;
std::uint32_t get_tracker_key(address const& iface) const;
void for_each_listen_socket(std::function<void(aux::listen_socket_handle const&)> f) override
{
for (auto& s : m_listen_sockets)
@ -906,11 +912,6 @@ namespace aux {
// the peer id that is generated at the start of the session
peer_id m_peer_id;
// the key is an id that is used to identify the
// client with the tracker only. It is randomized
// at startup
std::uint32_t m_key = 0;
// posts a notification when the set of local IPs changes
std::unique_ptr<ip_change_notifier> m_ip_notifier;

View File

@ -586,10 +586,13 @@ namespace libtorrent {
// the peer ID is randomized per peer.
peer_id id() const;
#ifndef TORRENT_NO_DEPRECATE
// deprecated in 1.2
// sets the key sent to trackers. If it's not set, it is initialized
// by libtorrent. The key may be used by the tracker to identify the
// peer potentially across you changing your IP.
void set_key(std::uint32_t key);
#endif
// built-in peer classes
static constexpr peer_class_t global_peer_class_id{0};

View File

@ -43,6 +43,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/file_storage.hpp"
#include "libtorrent/torrent_info.hpp"
#include <iostream>
using namespace lt;
using namespace sim;
@ -989,6 +991,30 @@ TORRENT_TEST(tracker_ipv6_argument)
TEST_EQUAL(got_ipv6, true);
}
TORRENT_TEST(tracker_key_argument)
{
std::set<std::string> keys;
tracker_test(
[](lt::add_torrent_params& p, lt::session& ses)
{
p.ti = make_torrent(true);
return 60;
},
[&](std::string method, std::string req
, std::map<std::string, std::string>& headers)
{
auto const pos = req.find("&key=");
TEST_CHECK(pos != std::string::npos);
keys.insert(req.substr(pos + 5, req.find_first_of('&', pos + 5) - pos - 5));
return sim::send_response(200, "OK", 11) + "d5:peers0:e";
}
, [](torrent_handle h) {}
, [](torrent_handle h) {});
// make sure we got two separate keys, one for each listen socket interface
TEST_EQUAL(keys.size(), 2);
}
// make sure we do _not_ send our IPv6 address to trackers for non-private
// torrents
TORRENT_TEST(tracker_ipv6_argument_non_private)

View File

@ -802,6 +802,13 @@ namespace {
p.set_str(settings_pack::peer_fingerprint, id.to_string());
apply_settings(std::move(p));
}
void session_handle::set_key(std::uint32_t)
{
// this is just a dummy function now, as we generate the key automatically
// per listen interface
}
#endif
peer_id session_handle::id() const
@ -809,11 +816,6 @@ namespace {
return sync_call_ret<peer_id>(&session_impl::get_peer_id);
}
void session_handle::set_key(std::uint32_t key)
{
async_call(&session_impl::set_key, key);
}
unsigned short session_handle::listen_port() const
{
return sync_call_ret<unsigned short, unsigned short(session_impl::*)() const>

View File

@ -1134,8 +1134,6 @@ namespace {
}
#endif
if (m_key) req.key = m_key;
#ifdef TORRENT_USE_OPENSSL
bool use_ssl = req.ssl_ctx != nullptr;
req.ssl_ctx = &m_ssl_ctx;
@ -1144,22 +1142,34 @@ namespace {
if (req.outgoing_socket)
{
auto ls = req.outgoing_socket.get();
req.listen_port = listen_port(ls);
req.key ^= ls->tracker_key;
req.listen_port =
#ifdef TORRENT_USE_OPENSSL
// SSL torrents use the SSL listen port
if (use_ssl) req.listen_port = ssl_listen_port(ls);
use_ssl ? ssl_listen_port(ls) :
#endif
listen_port(ls);
m_tracker_manager.queue_request(get_io_service(), req, c);
}
else
{
for (auto& ls : m_listen_sockets)
{
req.listen_port = listen_port(ls.get());
#ifdef TORRENT_USE_OPENSSL
if ((ls->ssl == transport::ssl) != use_ssl) continue;
#endif
req.listen_port =
#ifdef TORRENT_USE_OPENSSL
// SSL torrents use the SSL listen port
if (use_ssl) req.listen_port = ssl_listen_port(ls.get());
use_ssl ? ssl_listen_port(ls.get()) :
#endif
listen_port(ls.get());
// we combine the per-torrent key with the per-interface key to make
// them consistent and uniqiue per torrent and interface
req.key ^= ls->tracker_key;
req.outgoing_socket = ls;
m_tracker_manager.queue_request(get_io_service(), req, c);
}
@ -1384,6 +1394,25 @@ namespace {
reopen_outgoing_sockets();
}
std::uint32_t session_impl::get_tracker_key(address const& iface) const
{
uintptr_t const ses = reinterpret_cast<uintptr_t>(this);
hasher h(reinterpret_cast<char const*>(&ses), sizeof(ses));
if (iface.is_v4())
{
auto const b = iface.to_v4().to_bytes();
h.update({reinterpret_cast<char const*>(b.data()), b.size()});
}
else
{
auto const b = iface.to_v6().to_bytes();
h.update({reinterpret_cast<char const*>(b.data()), b.size()});
}
sha1_hash const hash = h.final();
unsigned char const* ptr = &hash[0];
return detail::read_uint32(ptr);
}
std::shared_ptr<listen_socket_t> session_impl::setup_listener(
listen_endpoint_t const& lep, error_code& ec)
{
@ -1591,6 +1620,8 @@ namespace {
}
return ret;
}
ret->tracker_key = get_tracker_key(ret->local_endpoint.address());
ret->tcp_external_port = ret->local_endpoint.port();
TORRENT_ASSERT(ret->tcp_external_port == bind_ep.port()
|| bind_ep.port() == 0);
@ -3006,11 +3037,6 @@ namespace {
m_peer_id = id;
}
void session_impl::set_key(std::uint32_t key)
{
m_key = key;
}
int session_impl::next_port() const
{
int start = m_settings.get_int(settings_pack::outgoing_port);
@ -5394,6 +5420,8 @@ namespace {
}
}
// TODO: 2 this function should be removed and users need to deal with the
// more generic case of having multiple listen ports
std::uint16_t session_impl::listen_port() const
{
return listen_port(nullptr);