From 496cf46b2591d7a6f533fa7726a2e883d1bbc77d Mon Sep 17 00:00:00 2001 From: Steven Siloti Date: Mon, 28 May 2018 17:15:02 -0700 Subject: [PATCH] enum_routes fixes on Linux --- src/enum_net.cpp | 116 +++++++++++++++++++++++++++-------------------- 1 file changed, 66 insertions(+), 50 deletions(-) diff --git a/src/enum_net.cpp b/src/enum_net.cpp index 5514e0350..ef9c384db 100644 --- a/src/enum_net.cpp +++ b/src/enum_net.cpp @@ -173,6 +173,52 @@ namespace { ); } +#if TORRENT_USE_GETIPFORWARDTABLE || TORRENT_USE_NETLINK + address build_netmask(int bits, int family) + { + if (family == AF_INET) + { + using bytes_t = boost::asio::ip::address_v4::bytes_type; + bytes_t b; + std::memset(&b[0], 0xff, b.size()); + for (int i = int(b.size()) - 1; i > 0; --i) + { + if (bits < 8) + { + b[i] <<= bits; + break; + } + b[i] = 0; + bits -= 8; + } + return address_v4(b); + } +#if TORRENT_USE_IPV6 + else if (family == AF_INET6) + { + using bytes_t = boost::asio::ip::address_v6::bytes_type; + bytes_t b; + std::memset(&b[0], 0xff, b.size()); + for (int i = int(b.size()) - 1; i > 0; --i) + { + if (bits < 8) + { + b[i] <<= bits; + break; + } + b[i] = 0; + bits -= 8; + } + return address_v6(b); + } +#endif + else + { + return address(); + } + } +#endif + #if TORRENT_USE_NETLINK int read_nl_sock(int sock, span buf, std::uint32_t const seq, std::uint32_t const pid) @@ -254,6 +300,16 @@ namespace { && rt_msg->rtm_table != RT_TABLE_LOCAL)) return false; +#if TORRENT_USE_IPV6 + // make sure the defaults have the right address family + // in case the attributes are not present + if (rt_msg->rtm_family == AF_INET6) + { + rt_info->gateway = address_v6(); + rt_info->destination = address_v6(); + } +#endif + int if_index = 0; int rt_len = int(RTM_PAYLOAD(nl_hdr)); #ifdef __clang__ @@ -298,16 +354,22 @@ namespace { #pragma clang diagnostic pop #endif +#if TORRENT_USE_IPV6 + if (rt_info->gateway.is_v6() && rt_info->gateway.to_v6().is_link_local()) + { + address_v6 gateway6 = rt_info->gateway.to_v6(); + gateway6.scope_id(if_index); + rt_info->gateway = gateway6; + } +#endif + ifreq req = {}; ::if_indextoname(std::uint32_t(if_index), req.ifr_name); static_assert(sizeof(rt_info->name) >= sizeof(req.ifr_name), "ip_route::name is too small"); std::memcpy(rt_info->name, req.ifr_name, sizeof(req.ifr_name)); ::ioctl(s, ::siocgifmtu, &req); rt_info->mtu = req.ifr_mtu; -// obviously this doesn't work correctly. How do you get the netmask for a route? -// if (ioctl(s, SIOCGIFNETMASK, &req) == 0) { -// rt_info->netmask = sockaddr_to_address(&req.ifr_addr, req.ifr_addr.sa_family); -// } + rt_info->netmask = build_netmask(rt_msg->rtm_dst_len, rt_msg->rtm_family); return true; } @@ -509,52 +571,6 @@ int _System __libsocket_sysctl(int* mib, u_int namelen, void *oldp, size_t *oldl return false; } -#if TORRENT_USE_GETIPFORWARDTABLE - address build_netmask(int bits, int family) - { - if (family == AF_INET) - { - using bytes_t = boost::asio::ip::address_v4::bytes_type; - bytes_t b; - std::memset(&b[0], 0xff, b.size()); - for (int i = int(b.size()) - 1; i > 0; --i) - { - if (bits < 8) - { - b[i] <<= bits; - break; - } - b[i] = 0; - bits -= 8; - } - return address_v4(b); - } -#if TORRENT_USE_IPV6 - else if (family == AF_INET6) - { - using bytes_t = boost::asio::ip::address_v6::bytes_type; - bytes_t b; - std::memset(&b[0], 0xff, b.size()); - for (int i = int(b.size()) - 1; i > 0; --i) - { - if (bits < 8) - { - b[i] <<= bits; - break; - } - b[i] = 0; - bits -= 8; - } - return address_v6(b); - } -#endif - else - { - return address(); - } - } -#endif - std::vector enum_net_interfaces(io_service& ios, error_code& ec) { TORRENT_UNUSED(ios); // this may be unused depending on configuration