diff options
| author | 2021-08-16 10:32:25 +0200 | |
|---|---|---|
| committer | 2021-08-16 10:32:25 +0200 | |
| commit | 70419f7a17880fd1e7834e7fe6e1aad14b0565bb (patch) | |
| tree | e1eb243069df47057ba98c77dcce4588bf34ae31 /src | |
| parent | configuration: fix mingw-w64 build (diff) | |
| download | yuzu-70419f7a17880fd1e7834e7fe6e1aad14b0565bb.tar.gz yuzu-70419f7a17880fd1e7834e7fe6e1aad14b0565bb.tar.xz yuzu-70419f7a17880fd1e7834e7fe6e1aad14b0565bb.zip | |
network: retrieve subnet mask and gateway info
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/nifm/nifm.cpp | 24 | ||||
| -rw-r--r-- | src/core/network/network.cpp | 11 | ||||
| -rw-r--r-- | src/core/network/network.h | 19 | ||||
| -rw-r--r-- | src/core/network/network_interface.cpp | 103 | ||||
| -rw-r--r-- | src/core/network/network_interface.h | 4 |
5 files changed, 137 insertions, 24 deletions
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 796c89d47..0a53c0c81 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "core/hle/service/nifm/nifm.h" | 11 | #include "core/hle/service/nifm/nifm.h" |
| 12 | #include "core/hle/service/service.h" | 12 | #include "core/hle/service/service.h" |
| 13 | #include "core/network/network.h" | 13 | #include "core/network/network.h" |
| 14 | #include "core/network/network_interface.h" | ||
| 14 | 15 | ||
| 15 | namespace Service::NIFM { | 16 | namespace Service::NIFM { |
| 16 | 17 | ||
| @@ -357,16 +358,10 @@ private: | |||
| 357 | static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting), | 358 | static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting), |
| 358 | "IpConfigInfo has incorrect size."); | 359 | "IpConfigInfo has incorrect size."); |
| 359 | 360 | ||
| 360 | auto ipv4 = Network::GetHostIPv4Address(); | 361 | IpConfigInfo ip_config_info{ |
| 361 | if (!ipv4) { | ||
| 362 | LOG_ERROR(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0"); | ||
| 363 | ipv4.emplace(Network::IPv4Address{0, 0, 0, 0}); | ||
| 364 | } | ||
| 365 | |||
| 366 | const IpConfigInfo ip_config_info{ | ||
| 367 | .ip_address_setting{ | 362 | .ip_address_setting{ |
| 368 | .is_automatic{true}, | 363 | .is_automatic{true}, |
| 369 | .current_address{*ipv4}, | 364 | .current_address{0, 0, 0, 0}, |
| 370 | .subnet_mask{255, 255, 255, 0}, | 365 | .subnet_mask{255, 255, 255, 0}, |
| 371 | .gateway{192, 168, 1, 1}, | 366 | .gateway{192, 168, 1, 1}, |
| 372 | }, | 367 | }, |
| @@ -377,6 +372,19 @@ private: | |||
| 377 | }, | 372 | }, |
| 378 | }; | 373 | }; |
| 379 | 374 | ||
| 375 | const auto iface = Network::GetSelectedNetworkInterface(); | ||
| 376 | if (iface) { | ||
| 377 | ip_config_info.ip_address_setting = | ||
| 378 | IpAddressSetting{.is_automatic{true}, | ||
| 379 | .current_address{Network::TranslateIPv4(iface->ip_address)}, | ||
| 380 | .subnet_mask{Network::TranslateIPv4(iface->subnet_mask)}, | ||
| 381 | .gateway{Network::TranslateIPv4(iface->gateway)}}; | ||
| 382 | |||
| 383 | } else { | ||
| 384 | LOG_ERROR(Service_NIFM, | ||
| 385 | "Couldn't get host network configuration info, using default values"); | ||
| 386 | } | ||
| 387 | |||
| 380 | IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)}; | 388 | IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)}; |
| 381 | rb.Push(ResultSuccess); | 389 | rb.Push(ResultSuccess); |
| 382 | rb.PushRaw<IpConfigInfo>(ip_config_info); | 390 | rb.PushRaw<IpConfigInfo>(ip_config_info); |
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp index 71583159a..4732d4485 100644 --- a/src/core/network/network.cpp +++ b/src/core/network/network.cpp | |||
| @@ -50,11 +50,6 @@ void Finalize() { | |||
| 50 | WSACleanup(); | 50 | WSACleanup(); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | constexpr IPv4Address TranslateIPv4(in_addr addr) { | ||
| 54 | auto& bytes = addr.S_un.S_un_b; | ||
| 55 | return IPv4Address{bytes.s_b1, bytes.s_b2, bytes.s_b3, bytes.s_b4}; | ||
| 56 | } | ||
| 57 | |||
| 58 | sockaddr TranslateFromSockAddrIn(SockAddrIn input) { | 53 | sockaddr TranslateFromSockAddrIn(SockAddrIn input) { |
| 59 | sockaddr_in result; | 54 | sockaddr_in result; |
| 60 | 55 | ||
| @@ -141,12 +136,6 @@ void Initialize() {} | |||
| 141 | 136 | ||
| 142 | void Finalize() {} | 137 | void Finalize() {} |
| 143 | 138 | ||
| 144 | constexpr IPv4Address TranslateIPv4(in_addr addr) { | ||
| 145 | const u32 bytes = addr.s_addr; | ||
| 146 | return IPv4Address{static_cast<u8>(bytes), static_cast<u8>(bytes >> 8), | ||
| 147 | static_cast<u8>(bytes >> 16), static_cast<u8>(bytes >> 24)}; | ||
| 148 | } | ||
| 149 | |||
| 150 | sockaddr TranslateFromSockAddrIn(SockAddrIn input) { | 139 | sockaddr TranslateFromSockAddrIn(SockAddrIn input) { |
| 151 | sockaddr_in result; | 140 | sockaddr_in result; |
| 152 | 141 | ||
diff --git a/src/core/network/network.h b/src/core/network/network.h index cfa68d478..fdd3e4655 100644 --- a/src/core/network/network.h +++ b/src/core/network/network.h | |||
| @@ -11,6 +11,12 @@ | |||
| 11 | #include "common/common_funcs.h" | 11 | #include "common/common_funcs.h" |
| 12 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | 13 | ||
| 14 | #ifdef _WIN32 | ||
| 15 | #include <winsock2.h> | ||
| 16 | #elif YUZU_UNIX | ||
| 17 | #include <netinet/in.h> | ||
| 18 | #endif | ||
| 19 | |||
| 14 | namespace Network { | 20 | namespace Network { |
| 15 | 21 | ||
| 16 | class Socket; | 22 | class Socket; |
| @@ -93,6 +99,19 @@ public: | |||
| 93 | ~NetworkInstance(); | 99 | ~NetworkInstance(); |
| 94 | }; | 100 | }; |
| 95 | 101 | ||
| 102 | #ifdef _WIN32 | ||
| 103 | constexpr IPv4Address TranslateIPv4(in_addr addr) { | ||
| 104 | auto& bytes = addr.S_un.S_un_b; | ||
| 105 | return IPv4Address{bytes.s_b1, bytes.s_b2, bytes.s_b3, bytes.s_b4}; | ||
| 106 | } | ||
| 107 | #elif YUZU_UNIX | ||
| 108 | constexpr IPv4Address TranslateIPv4(in_addr addr) { | ||
| 109 | const u32 bytes = addr.s_addr; | ||
| 110 | return IPv4Address{static_cast<u8>(bytes), static_cast<u8>(bytes >> 8), | ||
| 111 | static_cast<u8>(bytes >> 16), static_cast<u8>(bytes >> 24)}; | ||
| 112 | } | ||
| 113 | #endif | ||
| 114 | |||
| 96 | /// @brief Returns host's IPv4 address | 115 | /// @brief Returns host's IPv4 address |
| 97 | /// @return human ordered IPv4 address (e.g. 192.168.0.1) as an array | 116 | /// @return human ordered IPv4 address (e.g. 192.168.0.1) as an array |
| 98 | std::optional<IPv4Address> GetHostIPv4Address(); | 117 | std::optional<IPv4Address> GetHostIPv4Address(); |
diff --git a/src/core/network/network_interface.cpp b/src/core/network/network_interface.cpp index 75f4dc54f..b719da881 100644 --- a/src/core/network/network_interface.cpp +++ b/src/core/network/network_interface.cpp | |||
| @@ -2,11 +2,15 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | ||
| 6 | #include <fstream> | ||
| 7 | #include <sstream> | ||
| 5 | #include <vector> | 8 | #include <vector> |
| 6 | 9 | ||
| 7 | #include "common/bit_cast.h" | 10 | #include "common/bit_cast.h" |
| 8 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 9 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 13 | #include "common/settings.h" | ||
| 10 | #include "common/string_util.h" | 14 | #include "common/string_util.h" |
| 11 | #include "core/network/network_interface.h" | 15 | #include "core/network/network_interface.h" |
| 12 | 16 | ||
| @@ -29,8 +33,9 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() { | |||
| 29 | 33 | ||
| 30 | // retry up to 5 times | 34 | // retry up to 5 times |
| 31 | for (int i = 0; i < 5 && ret == ERROR_BUFFER_OVERFLOW; i++) { | 35 | for (int i = 0; i < 5 && ret == ERROR_BUFFER_OVERFLOW; i++) { |
| 32 | ret = GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, | 36 | ret = GetAdaptersAddresses( |
| 33 | nullptr, adapter_addresses.data(), &buf_size); | 37 | AF_INET, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_GATEWAYS, |
| 38 | nullptr, adapter_addresses.data(), &buf_size); | ||
| 34 | 39 | ||
| 35 | if (ret == ERROR_BUFFER_OVERFLOW) { | 40 | if (ret == ERROR_BUFFER_OVERFLOW) { |
| 36 | adapter_addresses.resize((buf_size / sizeof(IP_ADAPTER_ADDRESSES)) + 1); | 41 | adapter_addresses.resize((buf_size / sizeof(IP_ADAPTER_ADDRESSES)) + 1); |
| @@ -57,9 +62,26 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() { | |||
| 57 | *current_address->FirstUnicastAddress->Address.lpSockaddr) | 62 | *current_address->FirstUnicastAddress->Address.lpSockaddr) |
| 58 | .sin_addr; | 63 | .sin_addr; |
| 59 | 64 | ||
| 65 | ULONG mask = 0; | ||
| 66 | if (ConvertLengthToIpv4Mask(current_address->FirstUnicastAddress->OnLinkPrefixLength, | ||
| 67 | &mask) != NO_ERROR) { | ||
| 68 | LOG_ERROR(Network, "Failed to convert IPv4 prefix length to subnet mask"); | ||
| 69 | continue; | ||
| 70 | } | ||
| 71 | |||
| 72 | struct in_addr gateway = {0}; | ||
| 73 | if (current_address->FirstGatewayAddress != nullptr && | ||
| 74 | current_address->FirstGatewayAddress->Address.lpSockaddr != nullptr) { | ||
| 75 | gateway = Common::BitCast<struct sockaddr_in>( | ||
| 76 | *current_address->FirstGatewayAddress->Address.lpSockaddr) | ||
| 77 | .sin_addr; | ||
| 78 | } | ||
| 79 | |||
| 60 | result.push_back(NetworkInterface{ | 80 | result.push_back(NetworkInterface{ |
| 61 | .name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})}, | 81 | .name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})}, |
| 62 | .ip_address{ip_addr}}); | 82 | .ip_address{ip_addr}, |
| 83 | .subnet_mask = in_addr{.S_un{.S_addr{mask}}}, | ||
| 84 | .gateway = gateway}); | ||
| 63 | } | 85 | } |
| 64 | 86 | ||
| 65 | return result; | 87 | return result; |
| @@ -83,7 +105,7 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() { | |||
| 83 | } | 105 | } |
| 84 | 106 | ||
| 85 | for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { | 107 | for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { |
| 86 | if (ifa->ifa_addr == nullptr) { | 108 | if (ifa->ifa_addr == nullptr || ifa->ifa_netmask == nullptr) { |
| 87 | continue; | 109 | continue; |
| 88 | } | 110 | } |
| 89 | 111 | ||
| @@ -95,9 +117,59 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() { | |||
| 95 | continue; | 117 | continue; |
| 96 | } | 118 | } |
| 97 | 119 | ||
| 120 | std::uint32_t gateway{0}; | ||
| 121 | std::ifstream file{"/proc/net/route"}; | ||
| 122 | if (file.is_open()) { | ||
| 123 | |||
| 124 | // ignore header | ||
| 125 | file.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); | ||
| 126 | |||
| 127 | bool gateway_found = false; | ||
| 128 | |||
| 129 | for (std::string line; std::getline(file, line);) { | ||
| 130 | std::istringstream iss{line}; | ||
| 131 | |||
| 132 | std::string iface_name{}; | ||
| 133 | iss >> iface_name; | ||
| 134 | if (iface_name != ifa->ifa_name) { | ||
| 135 | continue; | ||
| 136 | } | ||
| 137 | |||
| 138 | iss >> std::hex; | ||
| 139 | |||
| 140 | std::uint32_t dest{0}; | ||
| 141 | iss >> dest; | ||
| 142 | if (dest != 0) { | ||
| 143 | // not the default route | ||
| 144 | continue; | ||
| 145 | } | ||
| 146 | |||
| 147 | iss >> gateway; | ||
| 148 | |||
| 149 | std::uint16_t flags{0}; | ||
| 150 | iss >> flags; | ||
| 151 | |||
| 152 | // flag RTF_GATEWAY (defined in <linux/route.h>) | ||
| 153 | if ((flags & 0x2) == 0) { | ||
| 154 | continue; | ||
| 155 | } | ||
| 156 | |||
| 157 | gateway_found = true; | ||
| 158 | break; | ||
| 159 | } | ||
| 160 | |||
| 161 | if (!gateway_found) { | ||
| 162 | gateway = 0; | ||
| 163 | } | ||
| 164 | } else { | ||
| 165 | LOG_ERROR(Network, "Failed to open \"/proc/net/route\""); | ||
| 166 | } | ||
| 167 | |||
| 98 | result.push_back(NetworkInterface{ | 168 | result.push_back(NetworkInterface{ |
| 99 | .name{ifa->ifa_name}, | 169 | .name{ifa->ifa_name}, |
| 100 | .ip_address{Common::BitCast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr}}); | 170 | .ip_address{Common::BitCast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr}, |
| 171 | .subnet_mask{Common::BitCast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr}, | ||
| 172 | .gateway{in_addr{.s_addr = gateway}}}); | ||
| 101 | } | 173 | } |
| 102 | 174 | ||
| 103 | freeifaddrs(ifaddr); | 175 | freeifaddrs(ifaddr); |
| @@ -107,4 +179,25 @@ std::vector<NetworkInterface> GetAvailableNetworkInterfaces() { | |||
| 107 | 179 | ||
| 108 | #endif | 180 | #endif |
| 109 | 181 | ||
| 182 | std::optional<NetworkInterface> GetSelectedNetworkInterface() { | ||
| 183 | const std::string& selected_network_interface = Settings::values.network_interface.GetValue(); | ||
| 184 | const auto network_interfaces = Network::GetAvailableNetworkInterfaces(); | ||
| 185 | if (network_interfaces.size() == 0) { | ||
| 186 | LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces"); | ||
| 187 | return {}; | ||
| 188 | } | ||
| 189 | |||
| 190 | const auto res = | ||
| 191 | std::ranges::find_if(network_interfaces, [&selected_network_interface](const auto& iface) { | ||
| 192 | return iface.name == selected_network_interface; | ||
| 193 | }); | ||
| 194 | |||
| 195 | if (res != network_interfaces.end()) { | ||
| 196 | return *res; | ||
| 197 | } else { | ||
| 198 | LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface); | ||
| 199 | return {}; | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 110 | } // namespace Network | 203 | } // namespace Network |
diff --git a/src/core/network/network_interface.h b/src/core/network/network_interface.h index d7184e14a..980edb2f5 100644 --- a/src/core/network/network_interface.h +++ b/src/core/network/network_interface.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <optional> | ||
| 7 | #include <string> | 8 | #include <string> |
| 8 | #include <vector> | 9 | #include <vector> |
| 9 | 10 | ||
| @@ -18,8 +19,11 @@ namespace Network { | |||
| 18 | struct NetworkInterface { | 19 | struct NetworkInterface { |
| 19 | std::string name; | 20 | std::string name; |
| 20 | struct in_addr ip_address; | 21 | struct in_addr ip_address; |
| 22 | struct in_addr subnet_mask; | ||
| 23 | struct in_addr gateway; | ||
| 21 | }; | 24 | }; |
| 22 | 25 | ||
| 23 | std::vector<NetworkInterface> GetAvailableNetworkInterfaces(); | 26 | std::vector<NetworkInterface> GetAvailableNetworkInterfaces(); |
| 27 | std::optional<NetworkInterface> GetSelectedNetworkInterface(); | ||
| 24 | 28 | ||
| 25 | } // namespace Network | 29 | } // namespace Network |