From 930af97d950d2b00f7d63701d1ecab2eeda9c73a Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sun, 14 Sep 2025 18:41:52 -0500 Subject: [PATCH] Common/Network: Add GetSubnetMask function. --- Source/Core/Common/Network.cpp | 65 +++++++++++++++++++++++++++++++++- Source/Core/Common/Network.h | 1 + 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/Source/Core/Common/Network.cpp b/Source/Core/Common/Network.cpp index 2d0e17492b..b4b50bb5a1 100644 --- a/Source/Core/Common/Network.cpp +++ b/Source/Core/Common/Network.cpp @@ -9,17 +9,21 @@ #include #ifndef _WIN32 +#include +#include +#include #include -#include #include #include #else #include +#include #endif #include #include "Common/BitUtils.h" +#include "Common/Buffer.h" #include "Common/CommonFuncs.h" #include "Common/Random.h" #include "Common/StringUtil.h" @@ -101,6 +105,65 @@ std::optional StringToBluetoothAddress(std::string_view str) return std::bit_cast(*result); } +std::optional GetSubnetMask(const IPAddress& address) +{ + std::optional result; + + // Android apparently does not provide getifaddrs. + // TODO: Provide an android implementation. +#if !defined(ANDROID) + const auto target_in_addr = std::bit_cast(address); + +#if defined(_WIN32) + static constexpr ULONG flags = GAA_FLAG_INCLUDE_PREFIX; + + // This is basically what Microsoft recommends. + Common::UniqueBuffer buffer(15000 / sizeof(IP_ADAPTER_ADDRESSES)); + auto buffer_size = ULONG(buffer.size() * sizeof(IP_ADAPTER_ADDRESSES)); + + if (GetAdaptersAddresses(AF_INET, flags, nullptr, buffer.data(), &buffer_size) != NO_ERROR) + return result; + + for (auto* addr = buffer.data(); addr != nullptr; addr = addr->Next) + { + for (auto* ua = addr->FirstUnicastAddress; ua != nullptr; ua = ua->Next) + { + auto* const sa = reinterpret_cast(ua->Address.lpSockaddr); + if (sa->sin_addr.s_addr != target_in_addr.s_addr) + continue; + + result = std::bit_cast(htonl(u32(-1) << (32 - ua->OnLinkPrefixLength))); + break; + } + } +#else + ifaddrs* ifaddrs{}; + if (getifaddrs(&ifaddrs) == -1) + return result; + + for (auto* ifa = ifaddrs; ifa != nullptr; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr->sa_family != AF_INET || ifa->ifa_addr == nullptr || + ifa->ifa_netmask == nullptr) + { + continue; + } + + auto* const ifaddr = reinterpret_cast(ifa->ifa_addr); + if (ifaddr->sin_addr.s_addr != target_in_addr.s_addr) + continue; + + auto* const mask = reinterpret_cast(ifa->ifa_netmask); + result = std::bit_cast(mask->sin_addr.s_addr); + break; + } + + freeifaddrs(ifaddrs); +#endif +#endif + return result; +} + EthernetHeader::EthernetHeader() = default; EthernetHeader::EthernetHeader(u16 ether_type) : ethertype(htons(ether_type)) diff --git a/Source/Core/Common/Network.h b/Source/Core/Common/Network.h index 91ed4c2513..6e415a4829 100644 --- a/Source/Core/Common/Network.h +++ b/Source/Core/Common/Network.h @@ -281,6 +281,7 @@ std::optional StringToMacAddress(std::string_view mac_string); std::string BluetoothAddressToString(BluetoothAddress bdaddr); std::optional StringToBluetoothAddress(std::string_view str); +std::optional GetSubnetMask(const IPAddress& address); u16 ComputeNetworkChecksum(const void* data, u16 length, u32 initial_value = 0); u16 ComputeTCPNetworkChecksum(const IPAddress& from, const IPAddress& to, const void* data, u16 length, u8 protocol);