network_interface.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. adapter_addresses.resize((buf_size / sizeof(IP_ADAPTER_ADDRESSES)) + 1);
  34. } else {
  35. break;
  36. }
  37. }
  38. if (ret == NO_ERROR) {
  39. std::vector<NetworkInterface> result;
  40. for (auto current_address = adapter_addresses.data(); current_address != nullptr;
  41. current_address = current_address->Next) {
  42. if (current_address->FirstUnicastAddress == nullptr ||
  43. current_address->FirstUnicastAddress->Address.lpSockaddr == nullptr) {
  44. continue;
  45. }
  46. if (current_address->OperStatus != IfOperStatusUp) {
  47. continue;
  48. }
  49. const auto ip_addr = Common::BitCast<struct sockaddr_in>(
  50. *current_address->FirstUnicastAddress->Address.lpSockaddr)
  51. .sin_addr;
  52. ULONG mask = 0;
  53. if (ConvertLengthToIpv4Mask(current_address->FirstUnicastAddress->OnLinkPrefixLength,
  54. &mask) != NO_ERROR) {
  55. LOG_ERROR(Network, "Failed to convert IPv4 prefix length to subnet mask");
  56. continue;
  57. }
  58. struct in_addr gateway = {.S_un{.S_addr{0}}};
  59. if (current_address->FirstGatewayAddress != nullptr &&
  60. current_address->FirstGatewayAddress->Address.lpSockaddr != nullptr) {
  61. gateway = Common::BitCast<struct sockaddr_in>(
  62. *current_address->FirstGatewayAddress->Address.lpSockaddr)
  63. .sin_addr;
  64. }
  65. result.push_back(NetworkInterface{
  66. .name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})},
  67. .ip_address{ip_addr},
  68. .subnet_mask = in_addr{.S_un{.S_addr{mask}}},
  69. .gateway = gateway});
  70. }
  71. return result;
  72. } else {
  73. LOG_ERROR(Network, "Failed to get network interfaces with GetAdaptersAddresses");
  74. return {};
  75. }
  76. }
  77. #else
  78. std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
  79. std::vector<NetworkInterface> result;
  80. struct ifaddrs* ifaddr = nullptr;
  81. if (getifaddrs(&ifaddr) != 0) {
  82. LOG_ERROR(Network, "Failed to get network interfaces with getifaddrs: {}",
  83. std::strerror(errno));
  84. return result;
  85. }
  86. for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
  87. if (ifa->ifa_addr == nullptr || ifa->ifa_netmask == nullptr) {
  88. continue;
  89. }
  90. if (ifa->ifa_addr->sa_family != AF_INET) {
  91. continue;
  92. }
  93. if ((ifa->ifa_flags & IFF_UP) == 0 || (ifa->ifa_flags & IFF_LOOPBACK) != 0) {
  94. continue;
  95. }
  96. std::uint32_t gateway{0};
  97. std::ifstream file{"/proc/net/route"};
  98. if (file.is_open()) {
  99. // ignore header
  100. file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
  101. bool gateway_found = false;
  102. for (std::string line; std::getline(file, line);) {
  103. std::istringstream iss{line};
  104. std::string iface_name{};
  105. iss >> iface_name;
  106. if (iface_name != ifa->ifa_name) {
  107. continue;
  108. }
  109. iss >> std::hex;
  110. std::uint32_t dest{0};
  111. iss >> dest;
  112. if (dest != 0) {
  113. // not the default route
  114. continue;
  115. }
  116. iss >> gateway;
  117. std::uint16_t flags{0};
  118. iss >> flags;
  119. // flag RTF_GATEWAY (defined in <linux/route.h>)
  120. if ((flags & 0x2) == 0) {
  121. continue;
  122. }
  123. gateway_found = true;
  124. break;
  125. }
  126. if (!gateway_found) {
  127. gateway = 0;
  128. }
  129. } else {
  130. LOG_ERROR(Network, "Failed to open \"/proc/net/route\"");
  131. }
  132. result.push_back(NetworkInterface{
  133. .name{ifa->ifa_name},
  134. .ip_address{Common::BitCast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr},
  135. .subnet_mask{Common::BitCast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr},
  136. .gateway{in_addr{.s_addr = gateway}}});
  137. }
  138. freeifaddrs(ifaddr);
  139. return result;
  140. }
  141. #endif
  142. std::optional<NetworkInterface> GetSelectedNetworkInterface() {
  143. const std::string& selected_network_interface = Settings::values.network_interface.GetValue();
  144. const auto network_interfaces = Network::GetAvailableNetworkInterfaces();
  145. if (network_interfaces.size() == 0) {
  146. LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces");
  147. return {};
  148. }
  149. const auto res =
  150. std::ranges::find_if(network_interfaces, [&selected_network_interface](const auto& iface) {
  151. return iface.name == selected_network_interface;
  152. });
  153. if (res != network_interfaces.end()) {
  154. return *res;
  155. } else {
  156. LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
  157. return {};
  158. }
  159. }
  160. } // namespace Network