feat: find interface index from ip address
This commit is contained in:
parent
9bcb86ebb0
commit
b4ad1f78fc
|
@ -16,8 +16,12 @@
|
|||
#include <utility> // std::pair
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h> // must come before iphlpapi.h
|
||||
#include <iphlpapi.h>
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/tcp.h> /* TCP_CONGESTION */
|
||||
#endif
|
||||
|
||||
|
@ -556,6 +560,92 @@ std::pair<tr_address, std::byte const*> tr_address::from_compact_ipv6(std::byte
|
|||
return { address, compact };
|
||||
}
|
||||
|
||||
std::optional<unsigned> tr_address::to_interface_index() const noexcept
|
||||
{
|
||||
if (!is_valid())
|
||||
{
|
||||
tr_logAddDebug("Invalid target address to find interface index");
|
||||
return {};
|
||||
}
|
||||
|
||||
tr_logAddDebug(fmt::format("Find interface index for {}", display_name()));
|
||||
|
||||
#ifdef _WIN32
|
||||
auto p_addresses = std::unique_ptr<void, void (*)(void*)>{ nullptr, operator delete };
|
||||
for (auto p_addesses_size = ULONG{ 15000 } /* 15KB */;;)
|
||||
{
|
||||
p_addresses.reset(operator new(p_addesses_size, std::nothrow));
|
||||
if (!p_addresses)
|
||||
{
|
||||
tr_logAddDebug("Could not allocate memory for interface list");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (auto ret = GetAdaptersAddresses(
|
||||
AF_UNSPEC,
|
||||
GAA_FLAG_SKIP_FRIENDLY_NAME,
|
||||
nullptr,
|
||||
reinterpret_cast<PIP_ADAPTER_ADDRESSES>(p_addresses.get()),
|
||||
&p_addesses_size);
|
||||
ret != ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
if (ret != ERROR_SUCCESS)
|
||||
{
|
||||
tr_logAddDebug(fmt::format("Failed to retrieve interface list: {} ({})", ret, tr_win32_format_message(ret)));
|
||||
return {};
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const* cur = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(p_addresses.get()); cur != nullptr; cur = cur->Next)
|
||||
{
|
||||
if (cur->OperStatus != IfOperStatusUp)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto const* sa_p = cur->FirstUnicastAddress; sa_p != nullptr; sa_p = sa_p->Next)
|
||||
{
|
||||
if (auto if_addr = tr_socket_address::from_sockaddr(sa_p->Address.lpSockaddr);
|
||||
if_addr && if_addr->address() == *this)
|
||||
{
|
||||
auto const ret = type == TR_AF_INET ? cur->IfIndex : cur->Ipv6IfIndex;
|
||||
tr_logAddDebug(fmt::format("Found interface index for {}: {}", display_name(), ret));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
struct ifaddrs* ifa = nullptr;
|
||||
if (getifaddrs(&ifa) != 0)
|
||||
{
|
||||
auto err = errno;
|
||||
tr_logAddDebug(fmt::format("Failed to retrieve interface list: {} ({})", err, tr_strerror(err)));
|
||||
return {};
|
||||
}
|
||||
auto const ifa_uniq = std::unique_ptr<ifaddrs, void (*)(struct ifaddrs*)>{ ifa, freeifaddrs };
|
||||
|
||||
for (; ifa != nullptr; ifa = ifa->ifa_next)
|
||||
{
|
||||
if (ifa->ifa_addr == nullptr || (ifa->ifa_flags & IFF_UP) == 0U)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto if_addr = tr_socket_address::from_sockaddr(ifa->ifa_addr); if_addr && if_addr->address() == *this)
|
||||
{
|
||||
auto const ret = if_nametoindex(ifa->ifa_name);
|
||||
tr_logAddDebug(fmt::format("Found interface index for {}: {}", display_name(), ret));
|
||||
return if_nametoindex(ifa->ifa_name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
tr_logAddDebug(fmt::format("Could not find interface index for {}", display_name()));
|
||||
return {};
|
||||
}
|
||||
|
||||
int tr_address::compare(tr_address const& that) const noexcept // <=>
|
||||
{
|
||||
// IPv6 addresses are always "greater than" IPv4
|
||||
|
|
|
@ -161,11 +161,11 @@ struct tr_address
|
|||
[[nodiscard]] static std::pair<tr_address, std::byte const*> from_compact_ipv4(std::byte const* compact) noexcept;
|
||||
[[nodiscard]] static std::pair<tr_address, std::byte const*> from_compact_ipv6(std::byte const* compact) noexcept;
|
||||
|
||||
// write the text form of the address, e.g. inet_ntop()
|
||||
// --- write the text form of the address, e.g. inet_ntop()
|
||||
std::string_view display_name(char* out, size_t outlen) const;
|
||||
[[nodiscard]] std::string display_name() const;
|
||||
|
||||
///
|
||||
// ---
|
||||
|
||||
[[nodiscard]] constexpr auto is_ipv4() const noexcept
|
||||
{
|
||||
|
@ -177,7 +177,7 @@ struct tr_address
|
|||
return type == TR_AF_INET6;
|
||||
}
|
||||
|
||||
/// bt protocol compact form
|
||||
// --- bt protocol compact form
|
||||
|
||||
// compact addr only -- used e.g. as `yourip` value in extension protocol handshake
|
||||
|
||||
|
@ -208,7 +208,11 @@ struct tr_address
|
|||
}
|
||||
}
|
||||
|
||||
// comparisons
|
||||
// ---
|
||||
|
||||
[[nodiscard]] std::optional<unsigned> to_interface_index() const noexcept;
|
||||
|
||||
// --- comparisons
|
||||
|
||||
[[nodiscard]] int compare(tr_address const& that) const noexcept;
|
||||
|
||||
|
@ -232,7 +236,7 @@ struct tr_address
|
|||
return this->compare(that) > 0;
|
||||
}
|
||||
|
||||
//
|
||||
// ---
|
||||
|
||||
[[nodiscard]] bool is_global_unicast_address() const noexcept;
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#ifdef _WIN32
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#include <sys/socket.h> /* socket(), bind() */
|
||||
#include <netinet/in.h> /* sockaddr_in */
|
||||
#include <sys/socket.h> /* socket(), bind() */
|
||||
#endif
|
||||
|
||||
#include <event2/event.h>
|
||||
|
@ -410,7 +410,7 @@ private:
|
|||
/* we want to join that LPD multicast group */
|
||||
struct ipv6_mreq mcast_req = {};
|
||||
mcast_req.ipv6mr_multiaddr = mcast6_addr_.sin6_addr;
|
||||
mcast_req.ipv6mr_interface = 0; //FIXME
|
||||
mcast_req.ipv6mr_interface = mediator_.bind_address(ip_protocol).to_interface_index().value_or(0);
|
||||
|
||||
if (setsockopt(
|
||||
sock,
|
||||
|
|
Loading…
Reference in New Issue