fix: misc net.cc and blocklist.cc fixes (#6717)

* fix: `tr_address` should be invalid by default

* fix: allow loopback address for LPD and incoming connections

* fix: `parseCidrline()` should set address type

* code review: keep `memcmp`
This commit is contained in:
Yat Ho 2024-03-25 06:09:51 +08:00 committed by GitHub
parent 9ddf609d50
commit 20aef2f79d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 32 additions and 22 deletions

View File

@ -339,7 +339,7 @@ void tr_announcerParseHttpAnnounceResponse(tr_announce_response& response, std::
{
BasicHandler::EndDict(context);
if (pex_.is_valid_for_peers())
if (pex_.is_valid())
{
response_.pex.push_back(pex_);
pex_ = {};

View File

@ -204,10 +204,12 @@ std::optional<address_range_t> parseCidrLine(std::string_view line)
return {};
}
auto const mask = uint32_t{ 0xFFFFFFFF } << (32 - *pflen);
auto const ip_u = htonl(addrpair.first.addr.addr4.s_addr);
addrpair.first.addr.addr4.s_addr = ntohl(ip_u & mask);
addrpair.second.addr.addr4.s_addr = ntohl(ip_u | (~mask));
auto const mask = ~(~uint32_t{ 0 } >> *pflen);
auto const ip_u = ntohl(addrpair.first.addr.addr4.s_addr);
auto tmp = htonl(ip_u & mask);
std::tie(addrpair.first, std::ignore) = tr_address::from_compact_ipv4(reinterpret_cast<std::byte*>(&tmp));
tmp = htonl(ip_u | (~mask));
std::tie(addrpair.second, std::ignore) = tr_address::from_compact_ipv4(reinterpret_cast<std::byte*>(&tmp));
return addrpair;
}

View File

@ -231,7 +231,7 @@ tr_peer_socket tr_netOpenPeerSocket(tr_session* session, tr_socket_address const
TR_ASSERT(addr.is_valid());
TR_ASSERT(!tr_peer_socket::limit_reached(session));
if (tr_peer_socket::limit_reached(session) || !session->allowsTCP() || !socket_address.is_valid_for_peers())
if (tr_peer_socket::limit_reached(session) || !session->allowsTCP() || !socket_address.is_valid())
{
return {};
}
@ -446,23 +446,29 @@ namespace is_valid_for_peers_helpers
/* isMartianAddr was written by Juliusz Chroboczek,
and is covered under the same license as third-party/dht/dht.c. */
[[nodiscard]] auto is_martian_addr(tr_address const& addr)
[[nodiscard]] auto is_martian_addr(tr_address const& addr, tr_peer_from from)
{
static auto constexpr Zeroes = std::array<unsigned char, 16>{};
auto const loopback_allowed = from == TR_PEER_FROM_INCOMING || from == TR_PEER_FROM_LPD || from == TR_PEER_FROM_RESUME;
switch (addr.type)
{
case TR_AF_INET:
{
auto const* const address = reinterpret_cast<unsigned char const*>(&addr.addr.addr4);
return address[0] == 0 || address[0] == 127 || (address[0] & 0xE0) == 0xE0;
return address[0] == 0 || // 0.x.x.x
(!loopback_allowed && address[0] == 127) || // 127.x.x.x
(address[0] & 0xE0) == 0xE0; // multicast address
}
case TR_AF_INET6:
{
auto const* const address = reinterpret_cast<unsigned char const*>(&addr.addr.addr6);
return address[0] == 0xFF ||
(memcmp(address, std::data(Zeroes), 15) == 0 && (address[15] == 0 || address[15] == 1));
return address[0] == 0xFF || // multicast address
(std::memcmp(address, std::data(Zeroes), 15) == 0 &&
(address[15] == 0 || // ::
(!loopback_allowed && address[15] == 1)) // ::1
);
}
default:
@ -703,12 +709,12 @@ std::string tr_socket_address::display_name(tr_address const& address, tr_port p
return fmt::format("[{:s}]:{:d}", address.display_name(), port.host());
}
bool tr_socket_address::is_valid_for_peers() const noexcept
bool tr_socket_address::is_valid_for_peers(tr_peer_from from) const noexcept
{
using namespace is_valid_for_peers_helpers;
return is_valid() && !std::empty(port_) && !is_ipv6_link_local_address(address_) && !is_ipv4_mapped_address(address_) &&
!is_martian_addr(address_);
!is_martian_addr(address_, from);
}
std::optional<tr_socket_address> tr_socket_address::from_sockaddr(struct sockaddr const* from)

View File

@ -60,6 +60,8 @@ using tr_socket_t = int;
#define sockerrno errno
#endif
#include "libtransmission/transmission.h" // tr_peer_from
#include "libtransmission/tr-assert.h"
#include "libtransmission/utils.h" // for tr_compare_3way()
@ -234,7 +236,7 @@ struct tr_address
[[nodiscard]] bool is_global_unicast_address() const noexcept;
tr_address_type type;
tr_address_type type = NUM_TR_AF_INET_TYPES;
union
{
struct in6_addr addr6;
@ -306,7 +308,7 @@ struct tr_socket_address
return address_.is_valid();
}
[[nodiscard]] bool is_valid_for_peers() const noexcept;
[[nodiscard]] bool is_valid_for_peers(tr_peer_from from) const noexcept;
[[nodiscard]] int compare(tr_socket_address const& that) const noexcept
{

View File

@ -129,11 +129,6 @@ std::shared_ptr<tr_peerIo> tr_peerIo::new_outgoing(
TR_ASSERT(socket_address.is_valid());
TR_ASSERT(utp || session->allowsTCP());
if (!socket_address.is_valid_for_peers())
{
return {};
}
auto peer_io = tr_peerIo::create(session, parent, &info_hash, false, is_seed);
auto const func = small::max_size_map<preferred_key_t, std::function<bool()>, TR_NUM_PREFERRED_TRANSPORT>{
{ TR_PREFER_UTP,

View File

@ -1439,7 +1439,7 @@ size_t tr_peerMgrAddPex(tr_torrent* tor, tr_peer_from from, tr_pex const* pex, s
for (tr_pex const* const end = pex + n_pex; pex != end; ++pex)
{
if (tr_isPex(pex) && /* safeguard against corrupt data */
!s->manager->blocklists_.contains(pex->socket_address.address()) && pex->is_valid_for_peers() &&
!s->manager->blocklists_.contains(pex->socket_address.address()) && pex->is_valid_for_peers(from) &&
from != TR_PEER_FROM_INCOMING && (from != TR_PEER_FROM_PEX || (pex->flags & ADDED_F_CONNECTABLE) != 0))
{
// we store this peer since it is supposedly connectable (socket address should be the peer's listening address)

View File

@ -517,9 +517,14 @@ struct tr_pex
return compare(that) < 0;
}
[[nodiscard]] bool is_valid_for_peers() const noexcept
[[nodiscard]] bool is_valid() const noexcept
{
return socket_address.is_valid_for_peers();
return socket_address.is_valid();
}
[[nodiscard]] bool is_valid_for_peers(tr_peer_from from) const noexcept
{
return socket_address.is_valid_for_peers(from);
}
tr_socket_address socket_address;