From 24f97fd221e1b857e24a76388b5a55f2ca15d342 Mon Sep 17 00:00:00 2001 From: TheLastRar Date: Mon, 10 May 2021 19:50:14 +0100 Subject: [PATCH] DEV9: Add internal DNS server --- pcsx2/CMakeLists.txt | 3 + pcsx2/DEV9/Config.h | 3 + pcsx2/DEV9/DEV9.h | 9 + pcsx2/DEV9/DEV9Config.cpp | 114 ++++++ pcsx2/DEV9/InternalServers/DNS_Server.cpp | 435 ++++++++++++++++++++++ pcsx2/DEV9/InternalServers/DNS_Server.h | 117 ++++++ pcsx2/DEV9/Linux/Config.cpp | 7 +- pcsx2/DEV9/Win32/DEV9WinConfig.cpp | 8 + pcsx2/DEV9/net.cpp | 34 ++ pcsx2/DEV9/net.h | 4 + pcsx2/pcsx2.vcxproj | 3 + pcsx2/pcsx2.vcxproj.filters | 9 + 12 files changed, 744 insertions(+), 2 deletions(-) create mode 100644 pcsx2/DEV9/DEV9Config.cpp create mode 100644 pcsx2/DEV9/InternalServers/DNS_Server.cpp create mode 100644 pcsx2/DEV9/InternalServers/DNS_Server.h diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index 6d0419e6bd..0898861cca 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -355,6 +355,7 @@ set(pcsx2DEV9Sources DEV9/ATA/ATA_Transfer.cpp DEV9/ATA/HddCreate.cpp DEV9/InternalServers/DHCP_Server.cpp + DEV9/InternalServers/DNS_Server.cpp DEV9/PacketReader/IP/UDP/DHCP/DHCP_Options.cpp DEV9/PacketReader/IP/UDP/DHCP/DHCP_Packet.cpp DEV9/PacketReader/IP/UDP/DNS/DNS_Classes.cpp @@ -366,6 +367,7 @@ set(pcsx2DEV9Sources DEV9/PacketReader/NetLib.cpp DEV9/smap.cpp DEV9/DEV9.cpp + DEV9/DEV9Config.cpp DEV9/flash.cpp DEV9/pcap_io.cpp DEV9/net.cpp @@ -378,6 +380,7 @@ set(pcsx2DEV9Headers DEV9/ATA/HddCreate.h DEV9/DEV9.h DEV9/InternalServers/DHCP_Server.cpp + DEV9/InternalServers/DNS_Server.h DEV9/net.h DEV9/PacketReader/IP/UDP/DHCP/DHCP_Options.h DEV9/PacketReader/IP/UDP/DHCP/DHCP_Packet.h diff --git a/pcsx2/DEV9/Config.h b/pcsx2/DEV9/Config.h index a1d98e55ad..e649886e37 100644 --- a/pcsx2/DEV9/Config.h +++ b/pcsx2/DEV9/Config.h @@ -15,3 +15,6 @@ void SaveConf(); void LoadConf(); + +void SaveDnsHosts(); +void LoadDnsHosts(); diff --git a/pcsx2/DEV9/DEV9.h b/pcsx2/DEV9/DEV9.h index 7876925c5f..c8363b20ec 100644 --- a/pcsx2/DEV9/DEV9.h +++ b/pcsx2/DEV9/DEV9.h @@ -55,6 +55,14 @@ bool rx_fifo_can_rx(); #define HDD_MIN_GB 40 #define HDD_MAX_GB 120 +struct ConfigHost +{ + std::string Url; + std::string Desc; + u8 Address[4]; + bool Enabled; +}; + struct ConfigDEV9 { char Eth[256]; @@ -69,6 +77,7 @@ struct ConfigDEV9 int AutoGateway; int AutoDNS1; int AutoDNS2; + std::vector EthHosts; #ifdef _WIN32 wchar_t Hdd[256]; #else diff --git a/pcsx2/DEV9/DEV9Config.cpp b/pcsx2/DEV9/DEV9Config.cpp new file mode 100644 index 0000000000..c0aecfd26f --- /dev/null +++ b/pcsx2/DEV9/DEV9Config.cpp @@ -0,0 +1,114 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2021 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 "ghc/filesystem.h" +#include + +#include "DEV9.h" +#include "gui/AppConfig.h" +#include "common/IniInterface.h" + +#ifdef _WIN32 +#include "ws2tcpip.h" +#elif defined(__POSIX__) +#include +#endif + +void SaveDnsHosts() +{ + std::unique_ptr hini(OpenFileConfig(GetSettingsFolder().Combine(wxString("DEV9Hosts.ini")).GetFullPath())); + IniSaver ini((wxConfigBase*)hini.get()); + + for (size_t i = 0; i < config.EthHosts.size(); i++) + { + std::wstring groupName(L"Host" + std::to_wstring(i)); + ScopedIniGroup iniEntry(ini, groupName); + ConfigHost entry = config.EthHosts[i]; + + wxString url(entry.Url); + ini.Entry(L"Url", url); + //TODO UTF8(?) + wxString desc(entry.Desc); + ini.Entry(L"Desc", desc); + + char addrBuff[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, entry.Address, addrBuff, INET_ADDRSTRLEN); + wxString address(addrBuff); + ini.Entry(L"Address", address); + + ini.Entry(L"Enabled", entry.Enabled); + } + ini.Flush(); +} + +void LoadDnsHosts() +{ + wxFileName iniPath = GetSettingsFolder().Combine(wxString("DEV9Hosts.ini")); + config.EthHosts.clear(); + //If no file exists, create one to provice an example config + if (!iniPath.FileExists()) + { + //Load Default settings + ConfigHost exampleHost; + exampleHost.Url = "www.example.com"; + exampleHost.Desc = "Set DNS to 192.0.2.1 to use this host list"; + memset(exampleHost.Address, 0, 4); + exampleHost.Enabled = false; + config.EthHosts.push_back(exampleHost); + SaveDnsHosts(); + return; + } + + std::unique_ptr hini(OpenFileConfig(iniPath.GetFullPath())); + IniLoader ini((wxConfigBase*)hini.get()); + + int i = 0; + while (true) + { + std::wstring groupName(L"Host" + std::to_wstring(i)); + ScopedIniGroup iniEntry(ini, groupName); + wxString tmp = wxEmptyString; + ini.Entry(L"Url", tmp, wxEmptyString); + //An empty url means we tried to read beyond end of the host list + if (tmp.IsEmpty()) + break; + + ConfigHost entry; + entry.Url = tmp.ToUTF8(); + + ini.Entry(L"Desc", tmp, wxEmptyString); + entry.Desc = tmp.ToUTF8(); + + ini.Entry(L"Address", tmp, L"0.0.0.0"); + + int ret = inet_pton(AF_INET, tmp.ToUTF8(), entry.Address); + //Only check Enabled if valid ip + if (ret != 1) + { + memset(entry.Address, 0, 4); + entry.Enabled = false; + } + else + ini.Entry(L"Enabled", entry.Enabled, false); + + if (entry.Enabled) + Console.WriteLn("DEV9: Host entry %i: url %s mapped to %s", i, entry.Url.c_str(), tmp.ToStdString().c_str()); + + config.EthHosts.push_back(entry); + i++; + } +} diff --git a/pcsx2/DEV9/InternalServers/DNS_Server.cpp b/pcsx2/DEV9/InternalServers/DNS_Server.cpp new file mode 100644 index 0000000000..217caa1afc --- /dev/null +++ b/pcsx2/DEV9/InternalServers/DNS_Server.cpp @@ -0,0 +1,435 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2021 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 +#include + +#ifdef _WIN32 +#include +#elif defined(__POSIX__) +//Note that getaddrinfo_a() exists which allows asynchronous operation +//however, that function is not standard POSIX, and is instead part of glibc +//So we will run with getaddrinfo() in a thread ourself +#include +#include +#include +#endif + +#include "DNS_Server.h" +#include "DEV9/PacketReader/IP/UDP/UDP_Packet.h" +#include "DEV9/PacketReader/IP/UDP/DNS/DNS_Packet.h" + +#include "DEV9/DEV9.h" + +using namespace PacketReader; +using namespace PacketReader::IP; +using namespace PacketReader::IP::UDP; +using namespace PacketReader::IP::UDP::DNS; + +namespace InternalServers +{ + DNS_Server::DNS_State::DNS_State(int count, std::vector dnsQuestions, DNS_Packet* dnsPacket, u16 port) + { + dns = dnsPacket; + counter.store(count); + questions = dnsQuestions; + clientPort = port; + + //Prefill unordered_map, allowing use to modify it from seperate threads + //See https://en.cppreference.com/w/cpp/container#Thread_safety + //Different elements in the same container can be modified concurrently by different threads + for (size_t i = 0; i < dnsQuestions.size(); i++) + answers[dnsQuestions[i]] = {0}; + } + + int DNS_Server::DNS_State::AddAnswer(const std::string& answer, IP_Address address) + { + answers[answer] = address; + return --counter; + } + int DNS_Server::DNS_State::AddNoAnswer(const std::string& answer) + { + return --counter; + } + + std::unordered_map DNS_Server::DNS_State::GetAnswers() + { + return answers; + } + + DNS_Server::DNS_Server(std::function receivedcallback) + : callback{receivedcallback} + { +#ifdef _WIN32 + /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */ + WORD wVersionRequested = MAKEWORD(2, 2); + + WSADATA wsaData{0}; + const int err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) + Console.Error("DEV9: WSAStartup failed with error: %d\n", err); + else + wsa_init = true; +#endif + } + + //We remap 127.0.0.1 to the PC's IP address + //We specificly use the address assigned to + //the adapter we are using +#ifdef _WIN32 + void DNS_Server::Init(PIP_ADAPTER_ADDRESSES adapter) +#elif defined(__POSIX__) + void DNS_Server::Init(ifaddrs* adapter) +#endif + { + localhostIP = {127, 0, 0, 1}; + //Find IPv4 Address +#ifdef _WIN32 + PIP_ADAPTER_UNICAST_ADDRESS address = nullptr; + if (adapter != nullptr) + { + PIP_ADAPTER_ADDRESSES info = (PIP_ADAPTER_ADDRESSES)adapter; + address = info->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; + localhostIP = *(IP_Address*)&sockaddr->sin_addr; + } + else + Console.Error("DEV9: Failed To Get Adapter IP"); +#elif defined(__POSIX__) + sockaddr* address = nullptr; + if (adapter != nullptr) + { + ifaddrs* info = (ifaddrs*)adapter; + if (info->ifa_addr != nullptr && info->ifa_addr->sa_family == AF_INET) + address = info->ifa_addr; + } + + if (address != nullptr) + { + sockaddr_in* sockaddr = (sockaddr_in*)address; + localhostIP = *(IP_Address*)&sockaddr->sin_addr; + } + else + Console.Error("DEV9: Failed To Get Adapter IP"); +#endif + + LoadHostList(); + } + + void DNS_Server::LoadHostList() + { + hosts.clear(); + for (size_t i = 0; i < config.EthHosts.size(); i++) + { + ConfigHost entry = config.EthHosts[i]; + if (entry.Enabled) + hosts.insert_or_assign(entry.Url, *(IP_Address*)entry.Address); + } + } + + UDP_Packet* DNS_Server::Recv() + { + UDP_Packet* retPay; + if (dnsQueue.Dequeue(&retPay)) + { + outstandingQueries--; + return retPay; + } + return nullptr; + } + + bool DNS_Server::Send(UDP_Packet* payload) + { + PayloadPtr* udpPayload = static_cast(payload->GetPayload()); + DNS_Packet dns(udpPayload->data, udpPayload->GetLength()); + + if (dns.GetOpCode() == (u8)DNS_OPCode::Query && dns.questions.size() > 0 && dns.GetQR() == false) + { + std::vector reqs; + + for (size_t i = 0; i < dns.questions.size(); i++) + { + DNS_QuestionEntry q = dns.questions[i]; + if (q.entryType == 1 && q.entryClass == 1) + reqs.push_back(q.name); + else + Console.Error("DEV9: Unexpected question type of class, T: %d C: %d", q.entryType, q.entryClass); + } + if (reqs.size() == 0) + return true; + if (dns.GetTC() == true) + { + Console.Error("DEV9: Truncated DNS packet Not Supported"); + return true; + } + + DNS_Packet* ret = new DNS_Packet(); + ret->id = dns.id; //TODO, drop duplicate requests based on ID + ret->SetQR(true); + ret->SetOpCode((u8)DNS_OPCode::Query); + ret->SetAA(false); + ret->SetTC(false); + ret->SetRD(true); + ret->SetRA(true); + ret->SetAD(false); + ret->SetCD(false); + ret->SetRCode((u8)DNS_RCode::NoError); + //Counts + ret->questions = dns.questions; + + DNS_State* state = new DNS_State(reqs.size(), reqs, ret, payload->sourcePort); + outstandingQueries++; + + for (size_t i = 0; i < reqs.size(); i++) + { + if (CheckHostList(reqs[i], state)) + continue; + GetHost(reqs[i], state); + } + return true; + } + else + { + Console.Error("DEV9: Unexpected DNS OPCode, Code: %s", dns.GetOpCode()); + return true; + } + } + + bool DNS_Server::CheckHostList(std::string url, DNS_State* state) + { + std::transform(url.begin(), url.end(), url.begin(), + [](unsigned char c) { return std::tolower(c); }); + + auto f = hosts.find(url); + if (f != hosts.end()) + { + const int remaining = state->AddAnswer(url, hosts[url]); + Console.WriteLn("DEV9: DNS: %s found in hosts", url.c_str()); + if (remaining == 0) + FinaliseDNS(state); + return true; + } + return false; + } + + void DNS_Server::FinaliseDNS(DNS_State* state) + { + DNS_Packet* retPay = state->dns; + std::vector reqs = state->questions; + std::unordered_map answers = state->GetAnswers(); + + for (size_t i = 0; i < reqs.size(); i++) + { + IP_Address ans = answers[reqs[i]]; + if (ans.integer != 0) + { + //TODO, might not be effective on pcap + const IP_Address local{127, 0, 0, 1}; + if (ans == local) + ans = localhostIP; + + std::vector ansVector; + ansVector.resize(4); + *(IP_Address*)&ansVector[0] = ans; + DNS_ResponseEntry ansEntry(reqs[i], 1, 1, ansVector, 10800); + retPay->answers.push_back(ansEntry); + } + else + retPay->SetRCode(2); //ServerFailure + } + + const u16 clientPort = state->clientPort; + delete state; + + if (retPay->GetLength() > 512) + { + Console.Error("DEV9: Generated DNS response too large, dropping"); + delete retPay; + outstandingQueries--; + return; + } + + UDP_Packet* retUdp = new UDP_Packet(retPay); + retUdp->sourcePort = 53; + retUdp->destinationPort = clientPort; + dnsQueue.Enqueue(retUdp); + callback(); + } + + DNS_Server::~DNS_Server() + { + //Block untill DNS finished & + //Delete entries in queue + while (outstandingQueries != 0) + { + UDP_Packet* retPay = nullptr; + if (!dnsQueue.Dequeue(&retPay)) + { + using namespace std::chrono_literals; + std::this_thread::sleep_for(10ms); + continue; + } + + delete retPay; + outstandingQueries--; + } + +#ifdef _WIN32 + if (wsa_init) + WSACleanup(); +#endif + } + +#ifdef _WIN32 + void DNS_Server::GetHost(std::string url, DNS_State* state) + { + //Need to convert to UTF16 + const int size = MultiByteToWideChar(CP_UTF8, 0, url.c_str(), -1, nullptr, 0); + std::vector converted_string(size); + MultiByteToWideChar(CP_UTF8, 0, url.c_str(), -1, converted_string.data(), converted_string.size()); + + ADDRINFOEX hints{0}; + hints.ai_family = AF_INET; + + GetAddrInfoExCallbackData* data = new GetAddrInfoExCallbackData(); + data->state = state; + data->session = this; + data->url = url; + + int ret = GetAddrInfoEx(converted_string.data(), nullptr, NS_ALL, 0, &hints, (ADDRINFOEX**)&data->result, nullptr, &data->overlapped, &DNS_Server::GetAddrInfoExCallback, &data->cancelHandle); + + if (ret == WSA_IO_PENDING) + return; + else + GetAddrInfoExCallback(ret, -1, &data->overlapped); + } + + void __stdcall DNS_Server::GetAddrInfoExCallback(DWORD dwError, DWORD dwBytes, OVERLAPPED* lpOverlapped) + { + GetAddrInfoExCallbackData* data = reinterpret_cast(lpOverlapped); + + int remaining = -1; + switch (dwError) + { + case NO_ERROR: + { + ADDRINFOEX* addrInfo = (ADDRINFOEX*)data->result; + while (addrInfo != nullptr && addrInfo->ai_family != AF_INET) + addrInfo = addrInfo->ai_next; + + if (addrInfo == nullptr) + { + Console.Error("DEV9: Internal DNS failed to find host %s", data->url.c_str()); + Console.Error("DEV9: with unexpected error code %d", -1); + remaining = data->state->AddNoAnswer(data->url); + break; + } + + sockaddr_in* sockaddr = (sockaddr_in*)addrInfo->ai_addr; + remaining = data->state->AddAnswer(data->url, *(IP_Address*)&sockaddr->sin_addr); + break; + } + case WSAHOST_NOT_FOUND: + case WSATRY_AGAIN: //Nonauthoritative host not found + Console.Error("DEV9: Internal DNS failed to find host %s", data->url.c_str()); + remaining = data->state->AddNoAnswer(data->url); + break; + default: + Console.Error("DEV9: Internal DNS failed to find host %s", data->url.c_str()); + Console.Error("DEV9: with unexpected error code %d", dwError); + remaining = data->state->AddNoAnswer(data->url); + break; + } + + pxAssert(remaining != -1); + + if (remaining == 0) + data->session->FinaliseDNS(data->state); + + //cleanup + if (data->result != nullptr) + FreeAddrInfoEx((ADDRINFOEX*)data->result); + delete data; + } +#elif defined(__POSIX__) + void DNS_Server::GetHost(std::string url, DNS_State* state) + { + //Need to spin up thread, pass the parms to it + + std::thread GetHostThread(&DNS_Server::GetAddrInfoThread, this, url, state); + //detatch thread so that it can clean up itself + //we use another method of waiting for thread compleation + GetHostThread.detach(); + } + + void DNS_Server::GetAddrInfoThread(std::string url, DNS_State* state) + { + addrinfo hints{0}; + hints.ai_family = AF_INET; + addrinfo* result = nullptr; + + int error = getaddrinfo(url.c_str(), nullptr, &hints, &result); + int remaining = -1; + switch (error) + { + case 0: + { + addrinfo* retInfo = result; + while (retInfo != nullptr && retInfo->ai_family != AF_INET) + retInfo = retInfo->ai_next; + + if (retInfo == nullptr) + { + Console.Error("DEV9: Internal DNS failed to find host %s", url.c_str()); + Console.Error("DEV9: with unexpected error code %d", -1); + remaining = state->AddNoAnswer(url); + break; + } + + sockaddr_in* sockaddr = (sockaddr_in*)retInfo->ai_addr; + remaining = state->AddAnswer(url, *(IP_Address*)&sockaddr->sin_addr); + break; + } + case EAI_NONAME: + case EAI_AGAIN: //Nonauthoritative host not found + Console.Error("DEV9: Internal DNS failed to find host %s", url.c_str()); + remaining = state->AddNoAnswer(url); + break; + default: + Console.Error("DEV9: Internal DNS failed to find host %s", url.c_str()); + Console.Error("DEV9: with unexpected error code %d", error); + remaining = state->AddNoAnswer(url); + break; + } + + pxAssert(remaining != -1); + + if (remaining == 0) + FinaliseDNS(state); + + //cleanup + if (result != nullptr) + freeaddrinfo(result); + } +#endif +} // namespace InternalServers diff --git a/pcsx2/DEV9/InternalServers/DNS_Server.h b/pcsx2/DEV9/InternalServers/DNS_Server.h new file mode 100644 index 0000000000..c83784eeef --- /dev/null +++ b/pcsx2/DEV9/InternalServers/DNS_Server.h @@ -0,0 +1,117 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2021 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 +#include +#include +#include + +#ifdef _WIN32 +#include +#endif + +#include "DEV9/SimpleQueue.h" + +#include "DEV9/PacketReader/IP/IP_Packet.h" +#include "DEV9/PacketReader/IP/UDP/UDP_Packet.h" +#include "DEV9/PacketReader/IP/UDP/DNS/DNS_Packet.h" + +#ifdef _WIN32 +#include +#include +#elif defined(__POSIX__) +#include +#include +#endif + +namespace InternalServers +{ + class DNS_Server + { + private: + class DNS_State + { + public: + std::atomic counter; + + std::vector questions; + PacketReader::IP::UDP::DNS::DNS_Packet* dns; + u16 clientPort; + + private: + std::unordered_map answers; + + public: + DNS_State(int count, std::vector dnsQuestions, PacketReader::IP::UDP::DNS::DNS_Packet* dnsPacket, u16 port); + + int AddAnswer(const std::string& answer, PacketReader::IP::IP_Address address); + int AddNoAnswer(const std::string& answer); + + std::unordered_map GetAnswers(); + }; + +#ifdef _WIN32 + bool wsa_init = false; +#endif + + std::function callback; + + PacketReader::IP::IP_Address localhostIP{127, 0, 0, 1}; + std::unordered_map hosts; + std::atomic outstandingQueries{0}; + SimpleQueue dnsQueue; + + public: + DNS_Server(std::function receivedcallback); + +#ifdef _WIN32 + void Init(PIP_ADAPTER_ADDRESSES adapter); +#elif defined(__POSIX__) + void Init(ifaddrs* adapter); +#endif + + //Recv + PacketReader::IP::UDP::UDP_Packet* Recv(); + //Expects a UDP_payload + bool Send(PacketReader::IP::UDP::UDP_Packet* payload); + + //This might block for a large amount of time + //if destruction takes place during DNS request + //and the OS configured DNS server is unreachable + ~DNS_Server(); + + private: + void LoadHostList(); + bool CheckHostList(std::string url, DNS_State* state); + void GetHost(std::string url, DNS_State* state); + void FinaliseDNS(DNS_State* state); + +#ifdef _WIN32 + struct GetAddrInfoExCallbackData + { + OVERLAPPED overlapped{0}; + void* result = nullptr; + HANDLE cancelHandle = nullptr; + DNS_State* state; + DNS_Server* session; + std::string url; + }; + + static void __stdcall GetAddrInfoExCallback(DWORD dwError, DWORD dwBytes, OVERLAPPED* lpOverlapped); +#elif defined(__POSIX__) + void GetAddrInfoThread(std::string url, DNS_State* state); +#endif + }; +} // namespace InternalServers diff --git a/pcsx2/DEV9/Linux/Config.cpp b/pcsx2/DEV9/Linux/Config.cpp index 121929ed87..a5add8c7b1 100644 --- a/pcsx2/DEV9/Linux/Config.cpp +++ b/pcsx2/DEV9/Linux/Config.cpp @@ -20,6 +20,7 @@ #include "DEV9/DEV9.h" #include "gui/AppConfig.h" +#include "DEV9/Config.h" #include #include @@ -31,7 +32,6 @@ void SaveConf() { - xmlDocPtr doc = NULL; /* document pointer */ xmlNodePtr root_node = NULL; char buff[256]; @@ -124,11 +124,12 @@ void SaveConf() *have been allocated by the parser. */ xmlCleanupParser(); + + SaveDnsHosts(); } void LoadConf() { - const std::string file(GetSettingsFolder().Combine(wxString("DEV9.cfg")).GetFullPath()); if (-1 == access(file.c_str(), F_OK)) return; @@ -222,4 +223,6 @@ void LoadConf() // free(configFile); xmlFreeDoc(doc); xmlCleanupParser(); + + LoadDnsHosts(); } diff --git a/pcsx2/DEV9/Win32/DEV9WinConfig.cpp b/pcsx2/DEV9/Win32/DEV9WinConfig.cpp index 6648f306f2..9e79a3cd34 100644 --- a/pcsx2/DEV9/Win32/DEV9WinConfig.cpp +++ b/pcsx2/DEV9/Win32/DEV9WinConfig.cpp @@ -21,6 +21,7 @@ #include "DEV9/DEV9.h" #include "gui/AppConfig.h" +#include "DEV9/Config.h" #include "ws2tcpip.h" @@ -81,13 +82,18 @@ void SaveConf() WritePrivateProfileInt(L"DEV9", L"ethEnable", config.ethEnable, file.c_str()); WritePrivateProfileInt(L"DEV9", L"hddEnable", config.hddEnable, file.c_str()); + + SaveDnsHosts(); } void LoadConf() { const std::wstring file(GetSettingsFolder().Combine(wxString("DEV9.cfg")).GetFullPath()); if (FileExists(file.c_str()) == false) + { + LoadDnsHosts(); return; + } wchar_t addrBuff[INET_ADDRSTRLEN] = {0}; wchar_t wEth[sizeof(config.Eth)] = {0}; @@ -123,4 +129,6 @@ void LoadConf() config.ethEnable = GetPrivateProfileInt(L"DEV9", L"ethEnable", config.ethEnable, file.c_str()); config.hddEnable = GetPrivateProfileInt(L"DEV9", L"hddEnable", config.hddEnable, file.c_str()); + + LoadDnsHosts(); } diff --git a/pcsx2/DEV9/net.cpp b/pcsx2/DEV9/net.cpp index 2c03ccda10..69377cf684 100644 --- a/pcsx2/DEV9/net.cpp +++ b/pcsx2/DEV9/net.cpp @@ -21,6 +21,7 @@ #if defined(__POSIX__) #include #endif + #include "net.h" #include "DEV9.h" #ifdef _WIN32 @@ -278,6 +279,8 @@ void NetAdapter::InitInternalServer(ifaddrs* adapter) if (config.InterceptDHCP) dhcpServer.Init(adapter); + + dnsServer.Init(adapter); if (blocks()) { @@ -297,6 +300,8 @@ void NetAdapter::ReloadInternalServer(ifaddrs* adapter) if (config.InterceptDHCP) dhcpServer.Init(adapter); + + dnsServer.Init(adapter); } bool NetAdapter::InternalServerRecv(NetPacket* pkt) @@ -314,6 +319,22 @@ bool NetAdapter::InternalServerRecv(NetPacket* pkt) frame.WritePacket(pkt); return true; } + + IP_Payload* ippay; + ippay = dnsServer.Recv(); + if (ippay != nullptr) + { + IP_Packet* ippkt = new IP_Packet(ippay); + ippkt->destinationIP = ps2IP; + ippkt->sourceIP = internalIP; + EthernetFrame frame(ippkt); + memcpy(frame.sourceMAC, internalMAC, 6); + memcpy(frame.destinationMAC, ps2MAC, 6); + frame.protocol = (u16)EtherType::IPv4; + frame.WritePacket(pkt); + return true; + } + return false; } @@ -340,6 +361,19 @@ bool NetAdapter::InternalServerSend(NetPacket* pkt) if (ippkt.destinationIP == internalIP) { + if (ippkt.protocol == (u16)IP_Type::UDP) + { + ps2IP = ippkt.sourceIP; + + IP_PayloadPtr* ipPayload = static_cast(ippkt.GetPayload()); + UDP_Packet udppkt(ipPayload->data, ipPayload->GetLength()); + + if (udppkt.destinationPort == 53) + { + //Send DNS + return dnsServer.Send(&udppkt); + } + } return true; } } diff --git a/pcsx2/DEV9/net.h b/pcsx2/DEV9/net.h index 7ed9d667d7..be1fc2f8f3 100644 --- a/pcsx2/DEV9/net.h +++ b/pcsx2/DEV9/net.h @@ -33,6 +33,7 @@ #include "PacketReader/IP/IP_Address.h" #include "InternalServers/DHCP_Server.h" +#include "InternalServers/DNS_Server.h" struct ConfigDEV9; @@ -87,6 +88,8 @@ protected: static const u8 internalMAC[6]; private: + //Only set if packet sent to the internal IP address + PacketReader::IP::IP_Address ps2IP{0}; std::thread internalRxThread; std::atomic internalRxThreadRunning{false}; @@ -95,6 +98,7 @@ private: bool internalRxHasData = false; InternalServers::DHCP_Server dhcpServer = InternalServers::DHCP_Server([&] { InternalSignalReceived(); }); + InternalServers::DNS_Server dnsServer = InternalServers::DNS_Server([&] { InternalSignalReceived(); }); public: NetAdapter(); diff --git a/pcsx2/pcsx2.vcxproj b/pcsx2/pcsx2.vcxproj index be13c26dbc..2402cb150e 100644 --- a/pcsx2/pcsx2.vcxproj +++ b/pcsx2/pcsx2.vcxproj @@ -276,9 +276,11 @@ + + @@ -724,6 +726,7 @@ + diff --git a/pcsx2/pcsx2.vcxproj.filters b/pcsx2/pcsx2.vcxproj.filters index 4aba084c73..8522dcffd2 100644 --- a/pcsx2/pcsx2.vcxproj.filters +++ b/pcsx2/pcsx2.vcxproj.filters @@ -1175,6 +1175,9 @@ System\Ps2\DEV9\ATA + + System\Ps2\DEV9 + System\Ps2\DEV9 @@ -1184,6 +1187,9 @@ System\Ps2\DEV9\InternalServers + + System\Ps2\DEV9\InternalServers + System\Ps2\DEV9\PacketReader\IP\UDP\DHCP @@ -2233,6 +2239,9 @@ System\Ps2\DEV9\InternalServers + + System\Ps2\DEV9\InternalServers + System\Ps2\DEV9