diff --git a/src/Components/Modules/DHT.cpp b/src/Components/Modules/DHT.cpp index 3fa5784a..96d07948 100644 --- a/src/Components/Modules/DHT.cpp +++ b/src/Components/Modules/DHT.cpp @@ -43,7 +43,6 @@ extern "C" int dht_gettimeofday(struct timeval *tp, struct timezone* /*tzp*/) namespace Components { - SOCKET DHT::Socket; std::mutex DHT::Mutex; std::vector DHT::Nodes; std::map, Utils::Slot)>> DHT::Handlers; @@ -66,6 +65,12 @@ namespace Components DHT::Handlers[hashStr] = callback; } + void DHT::BootstrapDone() + { + // Tell the game we got our external ip + Utils::Hook::Set(0x649D6F0, 1); + } + void DHT::Hash(std::string data, void* out, size_t size) { ZeroMemory(out, size); @@ -115,11 +120,10 @@ namespace Components } } - void DHT::OnData(std::string data, Network::Address address) + void DHT::OnData(char* buf, int len, sockaddr* from, int fromlen) { time_t tosleep = 0; - sockaddr addr = address.getSockAddr(); - dht_periodic(data.data(), data.size(), &addr, sizeof(addr), &tosleep, DHT::Callback, NULL); + dht_periodic(buf, len, from, fromlen, &tosleep, DHT::Callback, NULL); } void DHT::StoreNodes(bool force) @@ -213,29 +217,8 @@ namespace Components } } - void DHT::SocketFrame() - { - static char buffer[0x2001]; - - sockaddr_in addr; - int addrLen = sizeof(addr); - - while (true) - { - int len = recvfrom(DHT::Socket, buffer, sizeof buffer, 0, reinterpret_cast(&addr), &addrLen); - if (len <= 0) break; - - Network::Address address(&addr); - - std::string data(buffer, len); - DHT::OnData(data, address); - } - } - void DHT::RunFrame() { - DHT::SocketFrame(); - time_t tosleep = 0; dht_periodic(NULL, 0, NULL, 0, &tosleep, DHT::Callback, NULL); DHT::StoreNodes(false); @@ -256,36 +239,6 @@ namespace Components dht_ping_node(&addr, sizeof(addr)); } - void DHT::InitSocket() - { - WSAData data; - WSAStartup(MAKEWORD(2, 2), &data); - - DHT::Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - - int broadcastOn = 1; - setsockopt(DHT::Socket, SOL_SOCKET, SO_BROADCAST, LPSTR(&broadcastOn), sizeof(broadcastOn)); - - unsigned long nonBlocking = 1; - ioctlsocket(DHT::Socket, FIONBIO, &nonBlocking); - - sockaddr_in addr; - ZeroMemory(&addr, sizeof(addr)); - - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - - unsigned short port = DHT_PORT; - while (port < DHT_PORT + DHT_RANGE) - { - addr.sin_port = htons(port++); - if (bind(DHT::Socket, reinterpret_cast(&addr), sizeof(addr)) != SOCKET_ERROR) - { - break; - } - } - } - DHT::DHT() { // #ifdef DEBUG @@ -314,23 +267,22 @@ namespace Components Utils::IO::WriteFile(file, idData); } - DHT::InitSocket(); - dht_init(INT(DHT::Socket), -1, reinterpret_cast(idData.data()), reinterpret_cast("JC\0\0")); + dht_init(INT(*Game::ip_socket), -1, reinterpret_cast(idData.data()), reinterpret_cast("JC\0\0")); DHT::LoadNodes(); Scheduler::OnFrame(DHT::RunFrame); DHT::Bootstrap("router.bittorrent.com:6881"); - DHT::Bootstrap("router.utorrent.com:6881"); DHT::Bootstrap("dht.transmissionbt.com:6881"); - //DHT::Bootstrap("router.bitcomet.com:6881"); // Blacklisted DHT::Bootstrap("dht.aelitis.com:6881"); }); - DHT::Insert("IW4x", [](std::vector addresses) + auto callback = [](std::vector addresses) { std::lock_guard _(DHT::Mutex); + DHT::BootstrapDone(); + for (auto& address : addresses) { if (std::find(DHT::Nodes.begin(), DHT::Nodes.end(), address) == DHT::Nodes.end()) @@ -348,7 +300,9 @@ namespace Components Logger::Print("Received %s\n", address.getCString()); } - }); + }; + + DHT::Insert("xPROTO_IW4x", callback); Command::Add("addnode", [](Command::Params* params) { @@ -359,14 +313,11 @@ namespace Components }); } - DHT::~DHT() + void DHT::preDestroy() { DHT::Handlers.clear(); DHT::StoreNodes(true); dht_uninit(); - - closesocket(DHT::Socket); - WSACleanup(); } } diff --git a/src/Components/Modules/DHT.hpp b/src/Components/Modules/DHT.hpp index 315e8a66..cc772770 100644 --- a/src/Components/Modules/DHT.hpp +++ b/src/Components/Modules/DHT.hpp @@ -11,9 +11,9 @@ namespace Components typedef unsigned char Id[20]; DHT(); - ~DHT(); + void preDestroy() override; - static void OnData(std::string data, Network::Address address); + static void OnData(char* buf, int len, sockaddr* from, int fromlen); static void Insert(std::string data, Utils::Slot)> callback); @@ -28,8 +28,9 @@ namespace Components static void Hash(std::string data, void* out, size_t size); + static void BootstrapDone(); + private: - static SOCKET Socket; static std::mutex Mutex; static std::vector Nodes; static std::map, Utils::Slot)>> Handlers; @@ -39,9 +40,6 @@ namespace Components static void StoreNodes(bool force); static void LoadNodes(); - static void InitSocket(); - static void SocketFrame(); - static void Bootstrap(Network::Address node); }; } diff --git a/src/Components/Modules/Localization.cpp b/src/Components/Modules/Localization.cpp index 8a8232f7..09daf5a4 100644 --- a/src/Components/Modules/Localization.cpp +++ b/src/Components/Modules/Localization.cpp @@ -287,6 +287,8 @@ namespace Components } }); + Localization::Set("PLATFORM_POPUP_CONNECTION", "Connecting to the DHT network"); + // #ifndef DISABLE_ANTICHEAT // if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled() && !Utils::IsWineEnvironment() && !Loader::IsPerformingUnitTests()) // { diff --git a/src/Components/Modules/Network.cpp b/src/Components/Modules/Network.cpp index d0507922..8cb1749f 100644 --- a/src/Components/Modules/Network.cpp +++ b/src/Components/Modules/Network.cpp @@ -336,6 +336,52 @@ namespace Components } } + int __stdcall Network::SendTo(SOCKET s, const char * buf, int len, int flags, const sockaddr* to, int tolen) + { + static char buffer[0x20000]; + + if (len <= 4 || *reinterpret_cast(buf) != -1) + { + if (len + 4 > sizeof(buffer)) + { + Logger::Error("Network layer 1: Packet exceeds buffer length!\n"); + } + + std::memmove(buffer + 4, buf, len); + *reinterpret_cast(buffer) = -2; + + len += 4; + buf = buffer; + } + + return sendto(s, buf, len, flags, to, tolen); + } + + int __stdcall Network::RecvFrom(SOCKET s, char* buf, int len, int flags, sockaddr* from, int * fromlen) + { + int size = recvfrom(s, buf, len, flags, from, fromlen); + if (size >= 4) + { + int magic = *reinterpret_cast(buf); + + if (magic == -2) + { + size -= 4; + std::memmove(buf, buf + 4, size); + } + else if (magic != -1) + { + if (len > size) buf[size] = 0; + DHT::OnData(buf, size, from, *fromlen); + + size = -1; + WSASetLastError(WSAEWOULDBLOCK); + } + } + + return size; + } + Network::Network() { AssertSize(Game::netadr_t, 20); @@ -372,6 +418,10 @@ namespace Components // Install packet deploy hook Utils::Hook::RedirectJump(0x5AA713, Network::DeployPacketStub); + // Intercept the games native network IO interaction + Utils::Hook::Set(0x6D740C, Network::SendTo); + Utils::Hook::Set(0x6D7464, Network::RecvFrom); + Network::Handle("resolveAddress", [](Address address, std::string data) { Network::SendRaw(address, address.getString()); diff --git a/src/Components/Modules/Network.hpp b/src/Components/Modules/Network.hpp index b6beda23..e4e57d8a 100644 --- a/src/Components/Modules/Network.hpp +++ b/src/Components/Modules/Network.hpp @@ -89,6 +89,9 @@ namespace Components static void NetworkStartStub(); static void PacketErrorCheck(); + + static int __stdcall SendTo(SOCKET s, const char * buf, int len, int flags, const sockaddr* to, int tolen); + static int __stdcall RecvFrom(SOCKET s, char* buf, int len, int flags, sockaddr* from, int * fromlen); }; } diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index 99de880a..5a192416 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -259,7 +259,7 @@ namespace Components Utils::Hook::Nop(0x684080, 5); // Don't spam the console // spawn upnp thread when UPNP_init returns - Utils::Hook::Hook(0x47982B, []() + /*Utils::Hook::Hook(0x47982B, []() { std::thread([]() { @@ -271,10 +271,16 @@ namespace Components std::this_thread::sleep_for(500ms); } }).detach(); - }, HOOK_JUMP).install()->quick(); + }, HOOK_JUMP).install()->quick();*/ + + // Completely disable UPNP, as it conflicts with our new network protocol + Utils::Hook::Set(0x4797F2, 0xC3); // disable the IWNet IP detection (default 'got ipdetect' flag to 1) - Utils::Hook::Set(0x649D6F0, 1); + //Utils::Hook::Set(0x649D6F0, 1); + + // Tell the game we're already trying to receive our IP + Utils::Hook(0x48C5C0, 0x4513B4, HOOK_JUMP).install()->quick(); // Fix stats sleeping Utils::Hook::Set(0x6832BA, 0xEB);