feat: add `yourip` to extension protocol handshake (#4504)

* feat: add yourip to the extension protocol handshake
This commit is contained in:
Charles Kerr 2023-01-01 12:20:46 -06:00 committed by GitHub
parent db38f9aa2c
commit 611b181a99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 78 additions and 29 deletions

View File

@ -154,34 +154,58 @@ struct tr_address
std::string_view display_name(char* out, size_t outlen, tr_port port = {}) const;
[[nodiscard]] std::string display_name(tr_port port = {}) const;
template<typename OutputIt>
static OutputIt to_compact_ipv4(OutputIt out, in_addr const* addr4, tr_port port)
///
[[nodiscard]] constexpr auto is_ipv4() const noexcept
{
auto const nport = port.network();
out = std::copy_n(reinterpret_cast<std::byte const*>(addr4), sizeof(*addr4), out);
out = std::copy_n(reinterpret_cast<std::byte const*>(&nport), sizeof(nport), out);
return out;
return type == TR_AF_INET;
}
[[nodiscard]] constexpr auto is_ipv6() const noexcept
{
return type == TR_AF_INET6;
}
/// bt protocol compact form
// compact addr only -- used e.g. as `yourip` value in extension protocol handshake
template<typename OutputIt>
static OutputIt to_compact_ipv4(OutputIt out, in_addr const* addr4)
{
return std::copy_n(reinterpret_cast<std::byte const*>(addr4), sizeof(*addr4), out);
}
template<typename OutputIt>
static OutputIt to_compact_ipv4(OutputIt out, sockaddr_in const* sa4)
static OutputIt to_compact_ipv6(OutputIt out, in6_addr const* addr6)
{
return to_compact_ipv4(out, &sa4->sin_addr, tr_port::fromNetwork(sa4->sin_port));
return std::copy_n(reinterpret_cast<std::byte const*>(addr6), sizeof(*addr6), out);
}
template<typename OutputIt>
OutputIt to_compact(OutputIt out) const
{
return is_ipv4() ? to_compact_ipv4(out, &this->addr.addr4) : to_compact_ipv6(out, &this->addr.addr6);
}
// compact addr + port -- very common format used for peer exchange, dht, tracker announce responses
template<typename OutputIt>
static OutputIt to_compact_ipv4(OutputIt out, in_addr const* addr4, tr_port port)
{
out = tr_address::to_compact_ipv4(out, addr4);
auto const nport = port.network();
return std::copy_n(reinterpret_cast<std::byte const*>(&nport), sizeof(nport), out);
}
template<typename OutputIt>
static OutputIt to_compact_ipv6(OutputIt out, in6_addr const* addr6, tr_port port)
{
auto const nport = port.network();
out = std::copy_n(reinterpret_cast<std::byte const*>(addr6), sizeof(*addr6), out);
out = std::copy_n(reinterpret_cast<std::byte const*>(&nport), sizeof(nport), out);
return out;
}
out = tr_address::to_compact_ipv6(out, addr6);
template<typename OutputIt>
static OutputIt to_compact_ipv6(OutputIt out, sockaddr_in6 const* sa6)
{
return to_compact_ipv6(out, &sa6->sin6_addr, tr_port::fromNetwork(sa6->sin6_port));
auto const nport = port.network();
return std::copy_n(reinterpret_cast<std::byte const*>(&nport), sizeof(nport), out);
}
template<typename OutputIt>
@ -196,6 +220,26 @@ struct tr_address
return to_compact_ipv6(out, &this->addr.addr6, port);
}
template<typename OutputIt>
OutputIt to_compact(OutputIt out, tr_port port)
{
return is_ipv4() ? to_compact_4(out, &this->addr.addr4, port) : to_compact_ipv6(out, &this->addr.addr6, port);
}
// compact sockaddr helpers
template<typename OutputIt>
static OutputIt to_compact_ipv4(OutputIt out, sockaddr_in const* sa4)
{
return to_compact_ipv4(out, &sa4->sin_addr, tr_port::fromNetwork(sa4->sin_port));
}
template<typename OutputIt>
static OutputIt to_compact_ipv6(OutputIt out, sockaddr_in6 const* sa6)
{
return to_compact_ipv6(out, &sa6->sin6_addr, tr_port::fromNetwork(sa6->sin6_port));
}
template<typename OutputIt>
static OutputIt to_compact(OutputIt out, sockaddr const* saddr)
{
@ -209,16 +253,6 @@ struct tr_address
return to_compact(out, reinterpret_cast<struct sockaddr*>(ss));
}
[[nodiscard]] constexpr auto is_ipv4() const noexcept
{
return type == TR_AF_INET;
}
[[nodiscard]] constexpr auto is_ipv6() const noexcept
{
return type == TR_AF_INET6;
}
// comparisons
[[nodiscard]] int compare(tr_address const& that) const noexcept;

View File

@ -944,6 +944,19 @@ static void sendLtepHandshake(tr_peerMsgsImpl* msgs)
// libtorrent is 250.
tr_variantDictAddInt(&val, TR_KEY_reqq, ReqQ);
// https://www.bittorrent.org/beps/bep_0010.html
// A string containing the compact representation of the ip address this peer sees
// you as. i.e. this is the receiver's external ip address (no port is included).
// This may be either an IPv4 (4 bytes) or an IPv6 (16 bytes) address.
{
auto buf = std::array<std::byte, TR_ADDRSTRLEN>{};
auto const begin = std::data(buf);
auto const end = msgs->io->address().to_compact(begin);
auto const len = end - begin;
TR_ASSERT(len == 4 || len == 16);
tr_variantDictAddRaw(&val, TR_KEY_yourip, begin, len);
}
// http://bittorrent.org/beps/bep_0010.html
// Client name and version (as a utf-8 string). This is a much more
// reliable way of identifying the client than relying on the

View File

@ -18,7 +18,7 @@ using namespace std::literals;
namespace
{
auto constexpr MyStatic = std::array<std::string_view, 399>{ ""sv,
auto constexpr MyStatic = std::array<std::string_view, 400>{ ""sv,
"activeTorrentCount"sv,
"activity-date"sv,
"activityDate"sv,
@ -416,7 +416,8 @@ auto constexpr MyStatic = std::array<std::string_view, 399>{ ""sv,
"watch-dir"sv,
"watch-dir-enabled"sv,
"webseeds"sv,
"webseedsSendingToUs"sv };
"webseedsSendingToUs"sv,
"yourip"sv };
bool constexpr quarks_are_sorted()
{

View File

@ -420,6 +420,7 @@ enum
TR_KEY_watch_dir_enabled,
TR_KEY_webseeds,
TR_KEY_webseedsSendingToUs,
TR_KEY_yourip,
TR_N_KEYS
};