network_interface.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. // Copyright 2021 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <fstream>
  6. #include <sstream>
  7. #include <vector>
  8. #include "common/bit_cast.h"
  9. #include "common/common_types.h"
  10. #include "common/logging/log.h"
  11. #include "common/settings.h"
  12. #include "common/string_util.h"
  13. #include "core/network/network_interface.h"
  14. #ifdef _WIN32
  15. #include <iphlpapi.h>
  16. #else
  17. #include <cerrno>
  18. #include <ifaddrs.h>
  19. #include <net/if.h>
  20. #endif
  21. namespace Network {
  22. #ifdef _WIN32
  23. std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
  24. std::vector<IP_ADAPTER_ADDRESSES> adapter_addresses;
  25. DWORD ret = ERROR_BUFFER_OVERFLOW;
  26. DWORD buf_size = 0;
  27. // retry up to 5 times
  28. for (int i = 0; i < 5 && ret == ERROR_BUFFER_OVERFLOW; i++) {
  29. ret = GetAdaptersAddresses(
  30. AF_INET, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_GATEWAYS,
  31. nullptr, adapter_addresses.data(), &buf_size);
  32. if (ret != ERROR_BUFFER_OVERFLOW) {
  33. break;
  34. }
  35. adapter_addresses.resize((buf_size / sizeof(IP_ADAPTER_ADDRESSES)) + 1);
  36. }
  37. if (ret != NO_ERROR) {
  38. LOG_ERROR(Network, "Failed to get network interfaces with GetAdaptersAddresses");
  39. return {};
  40. }
  41. std::vector<NetworkInterface> result;
  42. for (auto current_address = adapter_addresses.data(); current_address != nullptr;
  43. current_address = current_address->Next) {
  44. if (current_address->FirstUnicastAddress == nullptr ||
  45. current_address->FirstUnicastAddress->Address.lpSockaddr == nullptr) {
  46. continue;
  47. }
  48. if (current_address->OperStatus != IfOperStatusUp) {
  49. continue;
  50. }
  51. const auto ip_addr = Common::BitCast<struct sockaddr_in>(
  52. *current_address->FirstUnicastAddress->Address.lpSockaddr)
  53. .sin_addr;
  54. ULONG mask = 0;
  55. if (ConvertLengthToIpv4Mask(current_address->FirstUnicastAddress->OnLinkPrefixLength,
  56. &mask) != NO_ERROR) {
  57. LOG_ERROR(Network, "Failed to convert IPv4 prefix length to subnet mask");
  58. continue;
  59. }
  60. struct in_addr gateway = {.S_un{.S_addr{0}}};
  61. if (current_address->FirstGatewayAddress != nullptr &&
  62. current_address->FirstGatewayAddress->Address.lpSockaddr != nullptr) {
  63. gateway = Common::BitCast<struct sockaddr_in>(
  64. *current_address->FirstGatewayAddress->Address.lpSockaddr)
  65. .sin_addr;
  66. }
  67. result.emplace_back(NetworkInterface{
  68. .name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})},
  69. .ip_address{ip_addr},
  70. .subnet_mask = in_addr{.S_un{.S_addr{mask}}},
  71. .gateway = gateway});
  72. }
  73. return result;
  74. }
  75. #else
  76. std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
  77. struct ifaddrs* ifaddr = nullptr;
  78. if (getifaddrs(&ifaddr) != 0) {
  79. LOG_ERROR(Network, "Failed to get network interfaces with getifaddrs: {}",
  80. std::strerror(errno));
  81. return {};
  82. }
  83. std::vector<NetworkInterface> result;
  84. for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
  85. if (ifa->ifa_addr == nullptr || ifa->ifa_netmask == nullptr) {
  86. continue;
  87. }
  88. if (ifa->ifa_addr->sa_family != AF_INET) {
  89. continue;
  90. }
  91. if ((ifa->ifa_flags & IFF_UP) == 0 || (ifa->ifa_flags & IFF_LOOPBACK) != 0) {
  92. continue;
  93. }
  94. u32 gateway{};
  95. std::ifstream file{"/proc/net/route"};
  96. if (!file.is_open()) {
  97. LOG_ERROR(Network, "Failed to open \"/proc/net/route\"");
  98. result.emplace_back(NetworkInterface{
  99. .name{ifa->ifa_name},
  100. .ip_address{Common::BitCast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr},
  101. .subnet_mask{Common::BitCast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr},
  102. .gateway{in_addr{.s_addr = gateway}}});
  103. continue;
  104. }
  105. // ignore header
  106. file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
  107. bool gateway_found = false;
  108. for (std::string line; std::getline(file, line);) {
  109. std::istringstream iss{line};
  110. std::string iface_name;
  111. iss >> iface_name;
  112. if (iface_name != ifa->ifa_name) {
  113. continue;
  114. }
  115. iss >> std::hex;
  116. u32 dest{};
  117. iss >> dest;
  118. if (dest != 0) {
  119. // not the default route
  120. continue;
  121. }
  122. iss >> gateway;
  123. u16 flags{};
  124. iss >> flags;
  125. // flag RTF_GATEWAY (defined in <linux/route.h>)
  126. if ((flags & 0x2) == 0) {
  127. continue;
  128. }
  129. gateway_found = true;
  130. break;
  131. }
  132. if (!gateway_found) {
  133. gateway = 0;
  134. }
  135. result.emplace_back(NetworkInterface{
  136. .name{ifa->ifa_name},
  137. .ip_address{Common::BitCast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr},
  138. .subnet_mask{Common::BitCast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr},
  139. .gateway{in_addr{.s_addr = gateway}}});
  140. }
  141. freeifaddrs(ifaddr);
  142. return result;
  143. }
  144. #endif
  145. std::optional<NetworkInterface> GetSelectedNetworkInterface() {
  146. const auto& selected_network_interface = Settings::values.network_interface.GetValue();
  147. const auto network_interfaces = Network::GetAvailableNetworkInterfaces();
  148. if (network_interfaces.size() == 0) {
  149. LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces");
  150. return std::nullopt;
  151. }
  152. const auto res =
  153. std::ranges::find_if(network_interfaces, [&selected_network_interface](const auto& iface) {
  154. return iface.name == selected_network_interface;
  155. });
  156. if (res == network_interfaces.end()) {
  157. LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
  158. return std::nullopt;
  159. }
  160. return *res;
  161. }
  162. } // namespace Network