From 35802f20896c2919dd6054a205956b37782096f5 Mon Sep 17 00:00:00 2001 From: TheLastRar Date: Tue, 24 May 2022 14:47:20 +0100 Subject: [PATCH] DEV9: Add AdapterUtils --- pcsx2/CMakeLists.txt | 2 + pcsx2/DEV9/AdapterUtils.cpp | 511 ++++++++++++++++++++++++++++++++ pcsx2/DEV9/AdapterUtils.h | 50 ++++ pcsx2/pcsx2.vcxproj | 2 + pcsx2/pcsx2.vcxproj.filters | 6 + pcsx2/pcsx2core.vcxproj | 2 + pcsx2/pcsx2core.vcxproj.filters | 6 + 7 files changed, 579 insertions(+) create mode 100644 pcsx2/DEV9/AdapterUtils.cpp create mode 100644 pcsx2/DEV9/AdapterUtils.h diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index de68c4a18f..20afcfc42c 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -343,6 +343,7 @@ set(pcsx2SPU2Headers # DEV9 sources set(pcsx2DEV9Sources + DEV9/AdapterUtils.cpp DEV9/ATA/Commands/ATA_Command.cpp DEV9/ATA/Commands/ATA_CmdDMA.cpp DEV9/ATA/Commands/ATA_CmdExecuteDeviceDiag.cpp @@ -387,6 +388,7 @@ set(pcsx2DEV9Sources # DEV9 headers set(pcsx2DEV9Headers + DEV9/AdapterUtils.h DEV9/ATA/ATA.h DEV9/ATA/HddCreate.h DEV9/DEV9.h diff --git a/pcsx2/DEV9/AdapterUtils.cpp b/pcsx2/DEV9/AdapterUtils.cpp new file mode 100644 index 0000000000..16b88aa6b3 --- /dev/null +++ b/pcsx2/DEV9/AdapterUtils.cpp @@ -0,0 +1,511 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2022 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" + +#include +#ifdef __POSIX__ +#include +#include +#include +#include +#include + +#include "common/StringUtil.h" + +#if defined(__FreeBSD__) || (__APPLE__) +#include +#include +#include +#include +#include + +#include "common/Assertions.h" + +#endif +#endif + +#include "AdapterUtils.h" + +using namespace PacketReader::IP; + +#ifdef _WIN32 +bool AdapterUtils::GetWin32Adapter(const std::string& name, PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr* buffer) +{ + int neededSize = 128; + std::unique_ptr AdapterInfo = std::make_unique(neededSize); + ULONG dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize; + + PIP_ADAPTER_ADDRESSES pAdapterInfo; + + DWORD dwStatus = GetAdaptersAddresses( + AF_UNSPEC, + GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS, + NULL, + AdapterInfo.get(), + &dwBufLen); + + if (dwStatus == ERROR_BUFFER_OVERFLOW) + { + DevCon.WriteLn("DEV9: GetWin32Adapter() buffer too small, resizing"); + neededSize = dwBufLen / sizeof(IP_ADAPTER_ADDRESSES) + 1; + AdapterInfo = std::make_unique(neededSize); + dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize; + DevCon.WriteLn("DEV9: New size %i", neededSize); + + dwStatus = GetAdaptersAddresses( + AF_UNSPEC, + GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS, + NULL, + AdapterInfo.get(), + &dwBufLen); + } + if (dwStatus != ERROR_SUCCESS) + return false; + + pAdapterInfo = AdapterInfo.get(); + + do + { + if (strcmp(pAdapterInfo->AdapterName, name.c_str()) == 0) + { + *adapter = *pAdapterInfo; + buffer->swap(AdapterInfo); + return true; + } + + pAdapterInfo = pAdapterInfo->Next; + } while (pAdapterInfo); + return false; +} +bool AdapterUtils::GetWin32AdapterAuto(PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr* buffer) +{ + int neededSize = 128; + std::unique_ptr AdapterInfo = std::make_unique(neededSize); + ULONG dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize; + + PIP_ADAPTER_ADDRESSES pAdapter; + + DWORD dwStatus = GetAdaptersAddresses( + AF_UNSPEC, + GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS, + NULL, + AdapterInfo.get(), + &dwBufLen); + + if (dwStatus == ERROR_BUFFER_OVERFLOW) + { + DevCon.WriteLn("DEV9: PCAPGetWin32Adapter() buffer too small, resizing"); + // + neededSize = dwBufLen / sizeof(IP_ADAPTER_ADDRESSES) + 1; + AdapterInfo = std::make_unique(neededSize); + dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize; + DevCon.WriteLn("DEV9: New size %i", neededSize); + + dwStatus = GetAdaptersAddresses( + AF_UNSPEC, + GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS, + NULL, + AdapterInfo.get(), + &dwBufLen); + } + + if (dwStatus != ERROR_SUCCESS) + return 0; + + pAdapter = AdapterInfo.get(); + + do + { + if (pAdapter->IfType != IF_TYPE_SOFTWARE_LOOPBACK && + pAdapter->OperStatus == IfOperStatusUp) + { + //Search for an adapter with; + //IPv4 Address + //DNS + //Gateway + + bool hasIPv4 = false; + bool hasDNS = false; + bool hasGateway = false; + + //IPv4 + if (GetAdapterIP(pAdapter).has_value()) + hasIPv4 = true; + + //DNS + if (GetDNS(pAdapter).size() > 0) + hasDNS = true; + + //Gateway + if (GetGateways(pAdapter).size() > 0) + hasGateway = true; + + if (hasIPv4 && hasDNS && hasGateway) + { + *adapter = *pAdapter; + buffer->swap(AdapterInfo); + return true; + } + } + + pAdapter = pAdapter->Next; + } while (pAdapter); + + return false; +} +#elif defined(__POSIX__) +bool AdapterUtils::GetIfAdapter(const std::string& name, ifaddrs* adapter, ifaddrs** buffer) +{ + ifaddrs* adapterInfo; + ifaddrs* pAdapter; + + int error = getifaddrs(&adapterInfo); + if (error) + return false; + + pAdapter = adapterInfo; + + do + { + if (pAdapter->ifa_addr->sa_family == AF_INET && strcmp(pAdapter->ifa_name, name.c_str()) == 0) + break; + + pAdapter = pAdapter->ifa_next; + } while (pAdapter); + + if (pAdapter != nullptr) + { + *adapter = *pAdapter; + *buffer = adapterInfo; + return true; + } + + freeifaddrs(adapterInfo); + return false; +} +bool AdapterUtils::GetIfAdapterAuto(ifaddrs* adapter, ifaddrs** buffer) +{ + ifaddrs* adapterInfo; + ifaddrs* pAdapter; + + int error = getifaddrs(&adapterInfo); + if (error) + return false; + + pAdapter = adapterInfo; + + do + { + if ((pAdapter->ifa_flags & IFF_LOOPBACK) == 0 && + (pAdapter->ifa_flags & IFF_UP) != 0) + { + //Search for an adapter with; + //IPv4 Address + //Gateway + + bool hasIPv4 = false; + bool hasGateway = false; + + if (GetAdapterIP(pAdapter).has_value()) + hasIPv4 = true; + + if (GetGateways(pAdapter).size() > 0) + hasGateway = true; + + if (hasIPv4 && hasGateway) + { + *adapter = *pAdapter; + *buffer = adapterInfo; + return true; + } + } + + pAdapter = pAdapter->ifa_next; + } while (pAdapter); + + freeifaddrs(adapterInfo); + return false; +} +#endif + +//AdapterIP +#ifdef _WIN32 +std::optional AdapterUtils::GetAdapterIP(PIP_ADAPTER_ADDRESSES adapter) +{ + PIP_ADAPTER_UNICAST_ADDRESS address = nullptr; + if (adapter != nullptr) + { + address = adapter->FirstUnicastAddress; + while (address != nullptr && address->Address.lpSockaddr->sa_family != AF_INET) + address = address->Next; + } + + if (address != nullptr) + { + sockaddr_in* sockaddr = (sockaddr_in*)address->Address.lpSockaddr; + return *(IP_Address*)&sockaddr->sin_addr; + } + return std::nullopt; +} +#elif defined(__POSIX__) +std::optional AdapterUtils::GetAdapterIP(ifaddrs* adapter) +{ + sockaddr* address = nullptr; + if (adapter != nullptr) + { + if (adapter->ifa_addr != nullptr && adapter->ifa_addr->sa_family == AF_INET) + address = adapter->ifa_addr; + } + + if (address != nullptr) + { + sockaddr_in* sockaddr = (sockaddr_in*)address; + return *(IP_Address*)&sockaddr->sin_addr; + } + return std::nullopt; +} +#endif + +//Gateways +#ifdef _WIN32 +std::vector AdapterUtils::GetGateways(PIP_ADAPTER_ADDRESSES adapter) +{ + if (adapter == nullptr) + return {}; + + std::vector collection; + + PIP_ADAPTER_GATEWAY_ADDRESS address = adapter->FirstGatewayAddress; + while (address != nullptr) + { + if (address->Address.lpSockaddr->sa_family == AF_INET) + { + sockaddr_in* sockaddr = (sockaddr_in*)address->Address.lpSockaddr; + collection.push_back(*(IP_Address*)&sockaddr->sin_addr); + } + address = address->Next; + } + + return collection; +} +#elif defined(__POSIX__) +#ifdef __linux__ +std::vector AdapterUtils::GetGateways(ifaddrs* adapter) +{ + ///proc/net/route contains some information about gateway addresses, + //and separates the information about by each interface. + if (adapter == nullptr) + return {}; + + std::vector collection; + std::vector routeLines; + std::fstream route("/proc/net/route", std::ios::in); + if (route.fail()) + { + route.close(); + Console.Error("DEV9: Failed to open /proc/net/route"); + return collection; + } + + std::string line; + while (std::getline(route, line)) + routeLines.push_back(line); + route.close(); + + //Columns are as follows (first-line header): + //Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT + for (size_t i = 1; i < routeLines.size(); i++) + { + std::string line = routeLines[i]; + if (line.rfind(adapter->ifa_name, 0) == 0) + { + std::vector split = StringUtil::SplitString(line, '\t', true); + std::string gatewayIPHex{split[2]}; + int addressValue = std::stoi(gatewayIPHex, 0, 16); + //Skip device routes without valid NextHop IP address + if (addressValue != 0) + { + IP_Address gwIP = *(IP_Address*)&addressValue; + collection.push_back(gwIP); + } + } + } + return collection; +} +#elif defined(__FreeBSD__) || (__APPLE__) +std::vector AdapterUtils::GetGateways(ifaddrs* adapter) +{ + if (adapter == nullptr) + return {}; + + std::vector collection; + + //Get index for our adapter by matching the adapter name + int ifIndex = -1; + + struct if_nameindex* ifNI; + ifNI = if_nameindex(); + if (ifNI == nullptr) + { + Console.Error("DEV9: if_nameindex Failed"); + return collection; + } + + struct if_nameindex* i = ifNI; + while (i->if_index != 0 && i->if_name != nullptr) + { + if (strcmp(i->if_name, adapter->ifa_name) == 0) + { + ifIndex = i->if_index; + break; + } + i++; + } + if_freenameindex(ifNI); + + //Check if we found the adapter + if (ifIndex == -1) + { + Console.Error("DEV9: Failed to get index for adapter"); + return collection; + } + + //Find the gateway by looking though the routing information + int name[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0}; + size_t bufferLen = 0; + + if (sysctl(name, 6, NULL, &bufferLen, NULL, 0) != 0) + { + Console.Error("DEV9: Failed to perform NET_RT_DUMP"); + return collection; + } + + //len is an estimate, double it to be safe + bufferLen *= 2; + std::unique_ptr buffer = std::make_unique(bufferLen); + + if (sysctl(name, 6, buffer.get(), &bufferLen, NULL, 0) != 0) + { + Console.Error("DEV9: Failed to perform NET_RT_DUMP"); + return collection; + } + + rt_msghdr* hdr; + for (size_t i = 0; i < bufferLen; i += hdr->rtm_msglen) + { + hdr = (rt_msghdr*)&buffer[i]; + + if (hdr->rtm_flags & RTF_GATEWAY && hdr->rtm_addrs & RTA_GATEWAY && (hdr->rtm_index == ifIndex)) + { + sockaddr* sockaddrs = (sockaddr*)(hdr + 1); + pxAssert(sockaddrs[RTAX_DST].sa_family == AF_INET); + + //Default gateway has no destination address + sockaddr_in* sockaddr = (sockaddr_in*)&sockaddrs[RTAX_DST]; + if (sockaddr->sin_addr.s_addr != 0) + continue; + + sockaddr = (sockaddr_in*)&sockaddrs[RTAX_GATEWAY]; + IP_Address gwIP = *(IP_Address*)&sockaddr->sin_addr; + collection.push_back(gwIP); + } + } + return collection; +} +#else +std::vector AdapterUtils::GetGateways(ifaddrs* adapter) +{ + Console.Error("DEV9: Unsupported OS, can't find Gateway"); + return {}; +} +#endif +#endif + +//DNS +#ifdef _WIN32 +std::vector AdapterUtils::GetDNS(PIP_ADAPTER_ADDRESSES adapter) +{ + if (adapter == nullptr) + return {}; + + std::vector collection; + + PIP_ADAPTER_DNS_SERVER_ADDRESS address = adapter->FirstDnsServerAddress; + while (address != nullptr) + { + if (address->Address.lpSockaddr->sa_family == AF_INET) + { + sockaddr_in* sockaddr = (sockaddr_in*)address->Address.lpSockaddr; + collection.push_back(*(IP_Address*)&sockaddr->sin_addr); + } + address = address->Next; + } + + return collection; +} +#elif defined(__POSIX__) +std::vector AdapterUtils::GetDNS(ifaddrs* adapter) +{ + //On Linux and OSX, DNS is system wide, not adapter specific, so we can ignore adapter + + // Parse /etc/resolv.conf for all of the "nameserver" entries. + // These are the DNS servers the machine is configured to use. + // On OSX, this file is not directly used by most processes for DNS + // queries/routing, but it is automatically generated instead, with + // the machine's DNS servers listed in it. + if (adapter == nullptr) + return {}; + + std::vector collection; + + std::fstream servers("/etc/resolv.conf", std::ios::in); + if (servers.fail()) + { + servers.close(); + Console.Error("DEV9: Failed to open /etc/resolv.conf"); + return collection; + } + + std::string line; + std::vector serversLines; + while (std::getline(servers, line)) + serversLines.push_back(line); + servers.close(); + + const IP_Address systemdDNS{127, 0, 0, 53}; + for (size_t i = 1; i < serversLines.size(); i++) + { + std::string line = serversLines[i]; + if (line.rfind("nameserver", 0) == 0) + { + std::vector split = StringUtil::SplitString(line, '\t', true); + if (split.size() == 1) + split = StringUtil::SplitString(line, ' ', true); + std::string dns{split[1]}; + + IP_Address address; + if (inet_pton(AF_INET, dns.c_str(), &address) != 1) + continue; + + if (address == systemdDNS) + Console.Error("DEV9: systemd-resolved DNS server is not supported"); + + collection.push_back(address); + } + } + return collection; +} +#endif diff --git a/pcsx2/DEV9/AdapterUtils.h b/pcsx2/DEV9/AdapterUtils.h new file mode 100644 index 0000000000..ee59034a22 --- /dev/null +++ b/pcsx2/DEV9/AdapterUtils.h @@ -0,0 +1,50 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2022 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once + +#ifdef _WIN32 +#include +#include +#elif defined(__POSIX__) +#include +#include +#endif + +#include +#include + +#include "DEV9/PacketReader/IP/IP_Address.h" + +namespace AdapterUtils +{ +#ifdef _WIN32 + bool GetWin32Adapter(const std::string& name, PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr* buffer); + bool GetWin32AdapterAuto(PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr* buffer); + + std::optional GetAdapterIP(PIP_ADAPTER_ADDRESSES adapter); + //Mask + std::vector GetGateways(PIP_ADAPTER_ADDRESSES adapter); + std::vector GetDNS(PIP_ADAPTER_ADDRESSES adapter); +#elif defined(__POSIX__) + bool GetIfAdapter(const std::string& name, ifaddrs* adapter, ifaddrs** buffer); + bool GetIfAdapterAuto(ifaddrs* adapter, ifaddrs** buffer); + + std::optional GetAdapterIP(ifaddrs* adapter); + //Mask + std::vector GetGateways(ifaddrs* adapter); + std::vector GetDNS(ifaddrs* adapter); +#endif +}; // namespace AdapterUtils diff --git a/pcsx2/pcsx2.vcxproj b/pcsx2/pcsx2.vcxproj index 05997e0a46..eb48490838 100644 --- a/pcsx2/pcsx2.vcxproj +++ b/pcsx2/pcsx2.vcxproj @@ -278,6 +278,7 @@ + @@ -755,6 +756,7 @@ + diff --git a/pcsx2/pcsx2.vcxproj.filters b/pcsx2/pcsx2.vcxproj.filters index 910c1771a9..adf3df9d11 100644 --- a/pcsx2/pcsx2.vcxproj.filters +++ b/pcsx2/pcsx2.vcxproj.filters @@ -1172,6 +1172,9 @@ System\Ps2\SPU2 + + System\Ps2\DEV9 + System\Ps2\DEV9\ATA\Commands @@ -2338,6 +2341,9 @@ Recording\Utilities + + System\Ps2\DEV9 + System\Ps2\DEV9\ATA diff --git a/pcsx2/pcsx2core.vcxproj b/pcsx2/pcsx2core.vcxproj index 1a7076ea14..8b28f463f2 100644 --- a/pcsx2/pcsx2core.vcxproj +++ b/pcsx2/pcsx2core.vcxproj @@ -143,6 +143,7 @@ + @@ -466,6 +467,7 @@ + diff --git a/pcsx2/pcsx2core.vcxproj.filters b/pcsx2/pcsx2core.vcxproj.filters index a1585b0fda..19b9f64a72 100644 --- a/pcsx2/pcsx2core.vcxproj.filters +++ b/pcsx2/pcsx2core.vcxproj.filters @@ -845,6 +845,9 @@ System\Ps2\SPU2 + + System\Ps2\DEV9 + System\Ps2\DEV9\ATA\Commands @@ -1661,6 +1664,9 @@ System\Ps2\SPU2 + + System\Ps2\DEV9 + System\Ps2\DEV9\ATA