mirror of https://github.com/PCSX2/pcsx2.git
DEV9: Add internal DNS server
This commit is contained in:
parent
ca3b857f22
commit
24f97fd221
|
@ -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
|
||||
|
|
|
@ -15,3 +15,6 @@
|
|||
|
||||
void SaveConf();
|
||||
void LoadConf();
|
||||
|
||||
void SaveDnsHosts();
|
||||
void LoadDnsHosts();
|
||||
|
|
|
@ -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<ConfigHost> EthHosts;
|
||||
#ifdef _WIN32
|
||||
wchar_t Hdd[256];
|
||||
#else
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "ghc/filesystem.h"
|
||||
#include <wx/fileconf.h>
|
||||
|
||||
#include "DEV9.h"
|
||||
#include "gui/AppConfig.h"
|
||||
#include "common/IniInterface.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "ws2tcpip.h"
|
||||
#elif defined(__POSIX__)
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
void SaveDnsHosts()
|
||||
{
|
||||
std::unique_ptr<wxFileConfig> 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<wxFileConfig> 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++;
|
||||
}
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <ws2tcpip.h>
|
||||
#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 <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#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<std::string> 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<std::string, IP_Address> DNS_Server::DNS_State::GetAnswers()
|
||||
{
|
||||
return answers;
|
||||
}
|
||||
|
||||
DNS_Server::DNS_Server(std::function<void()> 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<PayloadPtr*>(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<std::string> 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<std::string> reqs = state->questions;
|
||||
std::unordered_map<std::string, IP_Address> 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<u8> 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<wchar_t> 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<GetAddrInfoExCallbackData*>(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
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <minwinbase.h>
|
||||
#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 <winsock2.h>
|
||||
#include <iphlpapi.h>
|
||||
#elif defined(__POSIX__)
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
namespace InternalServers
|
||||
{
|
||||
class DNS_Server
|
||||
{
|
||||
private:
|
||||
class DNS_State
|
||||
{
|
||||
public:
|
||||
std::atomic<int> counter;
|
||||
|
||||
std::vector<std::string> questions;
|
||||
PacketReader::IP::UDP::DNS::DNS_Packet* dns;
|
||||
u16 clientPort;
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, PacketReader::IP::IP_Address> answers;
|
||||
|
||||
public:
|
||||
DNS_State(int count, std::vector<std::string> 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<std::string, PacketReader::IP::IP_Address> GetAnswers();
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
bool wsa_init = false;
|
||||
#endif
|
||||
|
||||
std::function<void()> callback;
|
||||
|
||||
PacketReader::IP::IP_Address localhostIP{127, 0, 0, 1};
|
||||
std::unordered_map<std::string, PacketReader::IP::IP_Address> hosts;
|
||||
std::atomic<int> outstandingQueries{0};
|
||||
SimpleQueue<PacketReader::IP::UDP::UDP_Packet*> dnsQueue;
|
||||
|
||||
public:
|
||||
DNS_Server(std::function<void()> 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
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "DEV9/DEV9.h"
|
||||
#include "gui/AppConfig.h"
|
||||
#include "DEV9/Config.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#if defined(__POSIX__)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include "net.h"
|
||||
#include "DEV9.h"
|
||||
#ifdef _WIN32
|
||||
|
@ -279,6 +280,8 @@ void NetAdapter::InitInternalServer(ifaddrs* adapter)
|
|||
if (config.InterceptDHCP)
|
||||
dhcpServer.Init(adapter);
|
||||
|
||||
dnsServer.Init(adapter);
|
||||
|
||||
if (blocks())
|
||||
{
|
||||
internalRxThreadRunning.store(true);
|
||||
|
@ -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<IP_PayloadPtr*>(ippkt.GetPayload());
|
||||
UDP_Packet udppkt(ipPayload->data, ipPayload->GetLength());
|
||||
|
||||
if (udppkt.destinationPort == 53)
|
||||
{
|
||||
//Send DNS
|
||||
return dnsServer.Send(&udppkt);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<bool> 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();
|
||||
|
|
|
@ -276,9 +276,11 @@
|
|||
<ClCompile Include="DEV9\ATA\ATA_State.cpp" />
|
||||
<ClCompile Include="DEV9\ATA\ATA_Transfer.cpp" />
|
||||
<ClCompile Include="DEV9\ATA\HddCreate.cpp" />
|
||||
<ClCompile Include="DEV9\DEV9Config.cpp" />
|
||||
<ClCompile Include="DEV9\DEV9.cpp" />
|
||||
<ClCompile Include="DEV9\flash.cpp" />
|
||||
<ClCompile Include="DEV9\InternalServers\DHCP_Server.cpp" />
|
||||
<ClCompile Include="DEV9\InternalServers\DNS_Server.cpp" />
|
||||
<ClCompile Include="DEV9\PacketReader\EthernetFrame.cpp" />
|
||||
<ClCompile Include="DEV9\PacketReader\IP\UDP\DHCP\DHCP_Options.cpp" />
|
||||
<ClCompile Include="DEV9\PacketReader\IP\UDP\DHCP\DHCP_Packet.cpp" />
|
||||
|
@ -724,6 +726,7 @@
|
|||
<ClInclude Include="DEV9\Config.h" />
|
||||
<ClInclude Include="DEV9\DEV9.h" />
|
||||
<ClInclude Include="DEV9\InternalServers\DHCP_Server.h" />
|
||||
<ClInclude Include="DEV9\InternalServers\DNS_Server.h" />
|
||||
<ClInclude Include="DEV9\net.h" />
|
||||
<ClInclude Include="DEV9\PacketReader\EthernetFrame.h" />
|
||||
<ClInclude Include="DEV9\PacketReader\IP\UDP\DHCP\DHCP_Options.h" />
|
||||
|
|
|
@ -1175,6 +1175,9 @@
|
|||
<ClCompile Include="DEV9\ATA\HddCreate.cpp">
|
||||
<Filter>System\Ps2\DEV9\ATA</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DEV9\DEV9Config.cpp">
|
||||
<Filter>System\Ps2\DEV9</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DEV9\DEV9.cpp">
|
||||
<Filter>System\Ps2\DEV9</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1184,6 +1187,9 @@
|
|||
<ClCompile Include="DEV9\InternalServers\DHCP_Server.cpp">
|
||||
<Filter>System\Ps2\DEV9\InternalServers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DEV9\InternalServers\DNS_Server.cpp">
|
||||
<Filter>System\Ps2\DEV9\InternalServers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DEV9\PacketReader\IP\UDP\DHCP\DHCP_Options.cpp">
|
||||
<Filter>System\Ps2\DEV9\PacketReader\IP\UDP\DHCP</Filter>
|
||||
</ClCompile>
|
||||
|
@ -2233,6 +2239,9 @@
|
|||
<ClInclude Include="DEV9\InternalServers\DHCP_Server.h">
|
||||
<Filter>System\Ps2\DEV9\InternalServers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DEV9\InternalServers\DNS_Server.h">
|
||||
<Filter>System\Ps2\DEV9\InternalServers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DEV9\net.h">
|
||||
<Filter>System\Ps2\DEV9</Filter>
|
||||
</ClInclude>
|
||||
|
|
Loading…
Reference in New Issue