forked from premiere/premiere-libtorrent
Use netlink to enumerate network interfaces on linux (#2105)
* move getting a table dump over netlink to a separate function * use netlink to enumerate network interfaces on linux
This commit is contained in:
parent
0a9e2c965d
commit
bbf361336b
|
@ -205,6 +205,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#define TORRENT_HAVE_MMAP 1
|
#define TORRENT_HAVE_MMAP 1
|
||||||
#define TORRENT_USE_NETLINK 1
|
#define TORRENT_USE_NETLINK 1
|
||||||
|
#define TORRENT_USE_IFADDRS 0
|
||||||
#define TORRENT_USE_IFCONF 1
|
#define TORRENT_USE_IFCONF 1
|
||||||
#define TORRENT_HAS_SALEN 0
|
#define TORRENT_HAS_SALEN 0
|
||||||
#define TORRENT_USE_FDATASYNC 1
|
#define TORRENT_USE_FDATASYNC 1
|
||||||
|
@ -214,10 +215,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#define TORRENT_ANDROID
|
#define TORRENT_ANDROID
|
||||||
#define TORRENT_HAS_FALLOCATE 0
|
#define TORRENT_HAS_FALLOCATE 0
|
||||||
#define TORRENT_USE_ICONV 0
|
#define TORRENT_USE_ICONV 0
|
||||||
#define TORRENT_USE_IFADDRS 0
|
|
||||||
#define TORRENT_USE_MEMALIGN 1
|
#define TORRENT_USE_MEMALIGN 1
|
||||||
#else // ANDROID
|
#else // ANDROID
|
||||||
#define TORRENT_USE_IFADDRS 1
|
|
||||||
#define TORRENT_USE_POSIX_MEMALIGN 1
|
#define TORRENT_USE_POSIX_MEMALIGN 1
|
||||||
|
|
||||||
// posix_fallocate() is available under this condition
|
// posix_fallocate() is available under this condition
|
||||||
|
|
268
src/enum_net.cpp
268
src/enum_net.cpp
|
@ -122,6 +122,7 @@ namespace libtorrent {namespace {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !TORRENT_USE_NETLINK
|
||||||
int sockaddr_len(sockaddr const* sin)
|
int sockaddr_len(sockaddr const* sin)
|
||||||
{
|
{
|
||||||
#if TORRENT_HAS_SALEN
|
#if TORRENT_HAS_SALEN
|
||||||
|
@ -148,6 +149,7 @@ namespace libtorrent {namespace {
|
||||||
#endif
|
#endif
|
||||||
return address();
|
return address();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool valid_addr_family(int family)
|
bool valid_addr_family(int family)
|
||||||
{
|
{
|
||||||
|
@ -160,7 +162,7 @@ namespace libtorrent {namespace {
|
||||||
|
|
||||||
#if TORRENT_USE_NETLINK
|
#if TORRENT_USE_NETLINK
|
||||||
|
|
||||||
int read_nl_sock(int sock, char *buf, int bufsize, std::uint32_t const seq, std::uint32_t const pid)
|
int read_nl_sock(int sock, span<char> buf, std::uint32_t const seq, std::uint32_t const pid)
|
||||||
{
|
{
|
||||||
nlmsghdr* nl_hdr;
|
nlmsghdr* nl_hdr;
|
||||||
|
|
||||||
|
@ -168,10 +170,11 @@ namespace libtorrent {namespace {
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
int read_len = int(recv(sock, buf, std::size_t(bufsize - msg_len), 0));
|
auto next_msg = buf.subspan(msg_len);
|
||||||
|
int read_len = int(recv(sock, next_msg.data(), next_msg.size(), 0));
|
||||||
if (read_len < 0) return -1;
|
if (read_len < 0) return -1;
|
||||||
|
|
||||||
nl_hdr = reinterpret_cast<nlmsghdr*>(buf);
|
nl_hdr = reinterpret_cast<nlmsghdr*>(next_msg.data());
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
|
@ -191,7 +194,6 @@ namespace libtorrent {namespace {
|
||||||
|
|
||||||
if (nl_hdr->nlmsg_type == NLMSG_DONE) break;
|
if (nl_hdr->nlmsg_type == NLMSG_DONE) break;
|
||||||
|
|
||||||
buf += read_len;
|
|
||||||
msg_len += read_len;
|
msg_len += read_len;
|
||||||
|
|
||||||
if ((nl_hdr->nlmsg_flags & NLM_F_MULTI) == 0) break;
|
if ((nl_hdr->nlmsg_flags & NLM_F_MULTI) == 0) break;
|
||||||
|
@ -199,6 +201,38 @@ namespace libtorrent {namespace {
|
||||||
return msg_len;
|
return msg_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum { NL_BUFSIZE = 8192 };
|
||||||
|
|
||||||
|
int nl_dump_request(int sock, int type, std::uint32_t seq, char family, span<char> msg, std::size_t msg_len)
|
||||||
|
{
|
||||||
|
nlmsghdr* nl_msg = reinterpret_cast<nlmsghdr*>(msg.data());
|
||||||
|
nl_msg->nlmsg_len = NLMSG_LENGTH(msg_len);
|
||||||
|
nl_msg->nlmsg_type = type;
|
||||||
|
nl_msg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
|
||||||
|
nl_msg->nlmsg_seq = seq;
|
||||||
|
// in theory nlmsg_pid should be set to the netlink port ID (NOT the process ID)
|
||||||
|
// of the sender, but the kernel ignores this field so it is typically set to
|
||||||
|
// zero
|
||||||
|
nl_msg->nlmsg_pid = 0;
|
||||||
|
// first byte of routing messages is always the family
|
||||||
|
msg[sizeof(nlmsghdr)] = family;
|
||||||
|
|
||||||
|
if (send(sock, nl_msg, nl_msg->nlmsg_len, 0) < 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the socket's port ID so that we can verify it in the repsonse
|
||||||
|
sockaddr_nl sock_addr;
|
||||||
|
socklen_t sock_addr_len = sizeof(sock_addr);
|
||||||
|
if (getsockname(sock, (sockaddr*)&sock_addr, &sock_addr_len) < 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return read_nl_sock(sock, msg, seq, sock_addr.nl_pid);
|
||||||
|
}
|
||||||
|
|
||||||
bool parse_route(int s, nlmsghdr* nl_hdr, ip_route* rt_info)
|
bool parse_route(int s, nlmsghdr* nl_hdr, ip_route* rt_info)
|
||||||
{
|
{
|
||||||
rtmsg* rt_msg = reinterpret_cast<rtmsg*>(NLMSG_DATA(nl_hdr));
|
rtmsg* rt_msg = reinterpret_cast<rtmsg*>(NLMSG_DATA(nl_hdr));
|
||||||
|
@ -262,6 +296,129 @@ namespace libtorrent {namespace {
|
||||||
// }
|
// }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int parse_nl_link(nlmsghdr* nl_hdr, ip_interface* link_info)
|
||||||
|
{
|
||||||
|
ifinfomsg* link_msg = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(nl_hdr));
|
||||||
|
|
||||||
|
link_info->name[0] = 0;
|
||||||
|
link_info->mtu = 0;
|
||||||
|
|
||||||
|
int rt_len = int(IFLA_PAYLOAD(nl_hdr));
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wcast-align"
|
||||||
|
#endif
|
||||||
|
for (rtattr* rt_attr = reinterpret_cast<rtattr*>(IFLA_RTA(link_msg));
|
||||||
|
RTA_OK(rt_attr, rt_len); rt_attr = RTA_NEXT(rt_attr, rt_len))
|
||||||
|
{
|
||||||
|
switch(rt_attr->rta_type)
|
||||||
|
{
|
||||||
|
case IFLA_MTU:
|
||||||
|
link_info->mtu = int(*reinterpret_cast<unsigned int*>(RTA_DATA(rt_attr)));
|
||||||
|
break;
|
||||||
|
case IFLA_IFNAME:
|
||||||
|
strncpy(link_info->name, reinterpret_cast<char*>(RTA_DATA(rt_attr)), sizeof(link_info->name));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return link_msg->ifi_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_nl_address(std::map<int, ip_interface> const& link_info, nlmsghdr* nl_hdr, ip_interface* ip_info)
|
||||||
|
{
|
||||||
|
ifaddrmsg* addr_msg = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(nl_hdr));
|
||||||
|
|
||||||
|
if (!valid_addr_family(addr_msg->ifa_family))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ip_info->preferred = (addr_msg->ifa_flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED | IFA_F_TENTATIVE)) == 0;
|
||||||
|
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
if (addr_msg->ifa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(addr_msg->ifa_prefixlen <= 128);
|
||||||
|
if (addr_msg->ifa_prefixlen > 0)
|
||||||
|
{
|
||||||
|
address_v6::bytes_type mask = {};
|
||||||
|
auto it = mask.begin();
|
||||||
|
if (addr_msg->ifa_prefixlen > 64)
|
||||||
|
{
|
||||||
|
detail::write_uint64(0xffffffffffffffffULL, it);
|
||||||
|
addr_msg->ifa_prefixlen -= 64;
|
||||||
|
}
|
||||||
|
if (addr_msg->ifa_prefixlen > 0)
|
||||||
|
{
|
||||||
|
std::uint64_t const m = ~((1ULL << (64 - addr_msg->ifa_prefixlen)) - 1);
|
||||||
|
detail::write_uint64(m, it);
|
||||||
|
}
|
||||||
|
ip_info->netmask = address_v6(mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(addr_msg->ifa_prefixlen <= 32);
|
||||||
|
if (addr_msg->ifa_prefixlen != 0)
|
||||||
|
{
|
||||||
|
std::uint32_t const m = ~((1U << (32 - addr_msg->ifa_prefixlen)) - 1);
|
||||||
|
ip_info->netmask = address_v4(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// intiialize name to be empty
|
||||||
|
ip_info->name[0] = '\0';
|
||||||
|
|
||||||
|
int rt_len = int(IFA_PAYLOAD(nl_hdr));
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wcast-align"
|
||||||
|
#endif
|
||||||
|
for (rtattr* rt_attr = reinterpret_cast<rtattr*>(IFA_RTA(addr_msg));
|
||||||
|
RTA_OK(rt_attr, rt_len); rt_attr = RTA_NEXT(rt_attr, rt_len))
|
||||||
|
{
|
||||||
|
switch(rt_attr->rta_type)
|
||||||
|
{
|
||||||
|
case IFA_ADDRESS:
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
if (addr_msg->ifa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
address_v6 addr = inaddr6_to_address(reinterpret_cast<in6_addr*>(RTA_DATA(rt_attr)));
|
||||||
|
if (addr_msg->ifa_scope == RT_SCOPE_LINK)
|
||||||
|
addr.scope_id(addr_msg->ifa_index);
|
||||||
|
ip_info->interface_address = addr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
ip_info->interface_address = inaddr_to_address(reinterpret_cast<in_addr*>(RTA_DATA(rt_attr)));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IFA_LABEL:
|
||||||
|
strncpy(ip_info->name, reinterpret_cast<char*>(RTA_DATA(rt_attr)), sizeof(ip_info->name));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto ifi_info = link_info.find(addr_msg->ifa_index);
|
||||||
|
if (ifi_info != link_info.end())
|
||||||
|
{
|
||||||
|
ip_info->mtu = ifi_info->second.mtu;
|
||||||
|
// for some reason IPv6 entries don't include an IFA_LABEL attribute
|
||||||
|
// so get it from the link in that case
|
||||||
|
if (ip_info->name[0] == '\0')
|
||||||
|
strncpy(ip_info->name, ifi_info->second.name, sizeof(ip_info->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
#endif // TORRENT_USE_NETLINK
|
#endif // TORRENT_USE_NETLINK
|
||||||
#endif // !BUILD_SIMULATOR
|
#endif // !BUILD_SIMULATOR
|
||||||
|
|
||||||
|
@ -451,7 +608,73 @@ namespace libtorrent {
|
||||||
wan.mtu = ios.sim().config().path_mtu(ip, ip);
|
wan.mtu = ios.sim().config().path_mtu(ip, ip);
|
||||||
ret.push_back(wan);
|
ret.push_back(wan);
|
||||||
}
|
}
|
||||||
|
#elif TORRENT_USE_NETLINK
|
||||||
|
int sock = socket(PF_ROUTE, SOCK_DGRAM, NETLINK_ROUTE);
|
||||||
|
if (sock < 0)
|
||||||
|
{
|
||||||
|
ec = error_code(errno, system_category());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t seq = 0;
|
||||||
|
std::map<int, ip_interface> link_info;
|
||||||
|
|
||||||
|
{
|
||||||
|
char msg[NL_BUFSIZE] = {};
|
||||||
|
nlmsghdr* nl_msg = reinterpret_cast<nlmsghdr*>(msg);
|
||||||
|
int len = nl_dump_request(sock, RTM_GETLINK, seq++, AF_UNSPEC, msg, sizeof(ifinfomsg));
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
ec = error_code(errno, system_category());
|
||||||
|
close(sock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wcast-align"
|
||||||
|
// NLMSG_OK uses signed/unsigned compare in the same expression
|
||||||
|
#pragma clang diagnostic ignored "-Wsign-compare"
|
||||||
|
#endif
|
||||||
|
for (; NLMSG_OK(nl_msg, len); nl_msg = NLMSG_NEXT(nl_msg, len))
|
||||||
|
{
|
||||||
|
ip_interface iface;
|
||||||
|
int ifi_index = parse_nl_link(nl_msg, &iface);
|
||||||
|
if (ifi_index >= 0) link_info.emplace(ifi_index, iface);
|
||||||
|
}
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char msg[NL_BUFSIZE] = {};
|
||||||
|
nlmsghdr* nl_msg = reinterpret_cast<nlmsghdr*>(msg);
|
||||||
|
int len = nl_dump_request(sock, RTM_GETADDR, seq++, AF_PACKET, msg, sizeof(ifaddrmsg));
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
ec = error_code(errno, system_category());
|
||||||
|
close(sock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wcast-align"
|
||||||
|
// NLMSG_OK uses signed/unsigned compare in the same expression
|
||||||
|
#pragma clang diagnostic ignored "-Wsign-compare"
|
||||||
|
#endif
|
||||||
|
for (; NLMSG_OK(nl_msg, len); nl_msg = NLMSG_NEXT(nl_msg, len))
|
||||||
|
{
|
||||||
|
ip_interface iface;
|
||||||
|
if (parse_nl_address(link_info, nl_msg, &iface)) ret.push_back(iface);
|
||||||
|
}
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
close(sock);
|
||||||
#elif TORRENT_USE_IFADDRS
|
#elif TORRENT_USE_IFADDRS
|
||||||
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
if (s < 0)
|
if (s < 0)
|
||||||
|
@ -1039,8 +1262,6 @@ namespace libtorrent {
|
||||||
// Free memory
|
// Free memory
|
||||||
free(routes);
|
free(routes);
|
||||||
#elif TORRENT_USE_NETLINK
|
#elif TORRENT_USE_NETLINK
|
||||||
enum { BUFSIZE = 8192 };
|
|
||||||
|
|
||||||
int sock = socket(PF_ROUTE, SOCK_DGRAM, NETLINK_ROUTE);
|
int sock = socket(PF_ROUTE, SOCK_DGRAM, NETLINK_ROUTE);
|
||||||
if (sock < 0)
|
if (sock < 0)
|
||||||
{
|
{
|
||||||
|
@ -1050,36 +1271,9 @@ namespace libtorrent {
|
||||||
|
|
||||||
std::uint32_t seq = 0;
|
std::uint32_t seq = 0;
|
||||||
|
|
||||||
char msg[BUFSIZE] = {};
|
char msg[NL_BUFSIZE] = {};
|
||||||
nlmsghdr* nl_msg = reinterpret_cast<nlmsghdr*>(msg);
|
nlmsghdr* nl_msg = reinterpret_cast<nlmsghdr*>(msg);
|
||||||
|
int len = nl_dump_request(sock, RTM_GETROUTE, seq++, AF_UNSPEC, msg, sizeof(rtmsg));
|
||||||
nl_msg->nlmsg_len = NLMSG_LENGTH(sizeof(rtmsg));
|
|
||||||
nl_msg->nlmsg_type = RTM_GETROUTE;
|
|
||||||
nl_msg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
|
|
||||||
nl_msg->nlmsg_seq = seq;
|
|
||||||
// in theory nlmsg_pid should be set to the netlink port ID (NOT the process ID)
|
|
||||||
// of the sender, but the kernel ignores this field so it is typically set to
|
|
||||||
// zero
|
|
||||||
nl_msg->nlmsg_pid = 0;
|
|
||||||
|
|
||||||
if (send(sock, nl_msg, nl_msg->nlmsg_len, 0) < 0)
|
|
||||||
{
|
|
||||||
ec = error_code(errno, system_category());
|
|
||||||
close(sock);
|
|
||||||
return std::vector<ip_route>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the socket's port ID so that we can verify it in the repsonse
|
|
||||||
sockaddr_nl sock_addr;
|
|
||||||
socklen_t sock_addr_len = sizeof(sock_addr);
|
|
||||||
if (getsockname(sock, (sockaddr*)&sock_addr, &sock_addr_len) < 0)
|
|
||||||
{
|
|
||||||
ec = error_code(errno, system_category());
|
|
||||||
close(sock);
|
|
||||||
return std::vector<ip_route>();
|
|
||||||
}
|
|
||||||
|
|
||||||
int len = read_nl_sock(sock, msg, BUFSIZE, seq, sock_addr.nl_pid);
|
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
{
|
{
|
||||||
ec = error_code(errno, system_category());
|
ec = error_code(errno, system_category());
|
||||||
|
@ -1087,10 +1281,6 @@ namespace libtorrent {
|
||||||
return std::vector<ip_route>();
|
return std::vector<ip_route>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// seq should be incremented between requests so do it here
|
|
||||||
// just in case someone adds another send below
|
|
||||||
++seq;
|
|
||||||
|
|
||||||
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
if (s < 0)
|
if (s < 0)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue