mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
[O] Filter GetIpAddrTable to selected network adapter (#724)
## Description of change Filter GetIpAddrTable to selected network adapter. Fixes the IP address error (5-1506-0000) on gitadora gw delta when multiple network adapters are present. ## Testing Tested on Gitadora GW Delta with both WiFi and Tailscale adapters present.
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "avs/core.h"
|
||||
#include "avs/ea3.h"
|
||||
@@ -18,12 +19,14 @@
|
||||
|
||||
// hooking related stuff
|
||||
static decltype(GetAdaptersInfo) *GetAdaptersInfo_orig = nullptr;
|
||||
static decltype(GetIpAddrTable) *GetIpAddrTable_orig = nullptr;
|
||||
static decltype(bind) *bind_orig = nullptr;
|
||||
|
||||
// settings
|
||||
std::string NETWORK_ADDRESS = "10.9.0.0";
|
||||
std::string NETWORK_SUBNET = "255.255.0.0";
|
||||
static bool GetAdaptersInfo_log = true;
|
||||
static bool GetIpAddrTable_log = true;
|
||||
|
||||
// network structs
|
||||
static struct in_addr network;
|
||||
@@ -43,6 +46,80 @@ static void defer_network_adapter_error() {
|
||||
});
|
||||
}
|
||||
|
||||
static bool is_valid_ipaddr_row(const MIB_IPADDRROW &row) {
|
||||
static const auto loopback = inet_addr("127.0.0.1");
|
||||
|
||||
return row.dwAddr != 0 && row.dwAddr != loopback;
|
||||
}
|
||||
|
||||
static MIB_IPADDRROW *find_preferred_ipaddr_row(PMIB_IPADDRTABLE table) {
|
||||
|
||||
if (table == nullptr || table->dwNumEntries == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// prefer the row matching -adapternetwork/-adaptersubnet
|
||||
for (DWORD i = 0; i < table->dwNumEntries; i++) {
|
||||
auto &row = table->table[i];
|
||||
if (!is_valid_ipaddr_row(row)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto row_prefix = row.dwAddr & row.dwMask;
|
||||
if (row_prefix == prefix.s_addr && row.dwMask == subnet.s_addr) {
|
||||
return &row;
|
||||
}
|
||||
}
|
||||
|
||||
// fall back to the interface Windows would route through by default
|
||||
PMIB_IPFORWARDTABLE pIpForwardTable = (MIB_IPFORWARDTABLE *) malloc(sizeof(MIB_IPFORWARDTABLE));
|
||||
DWORD dwSize = 0;
|
||||
if (GetIpForwardTable(pIpForwardTable, &dwSize, TRUE) == ERROR_INSUFFICIENT_BUFFER) {
|
||||
free(pIpForwardTable);
|
||||
pIpForwardTable = (MIB_IPFORWARDTABLE *) malloc(dwSize);
|
||||
}
|
||||
if (GetIpForwardTable(pIpForwardTable, &dwSize, TRUE) != NO_ERROR || pIpForwardTable->dwNumEntries == 0) {
|
||||
free(pIpForwardTable);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DWORD best = pIpForwardTable->table[0].dwForwardIfIndex;
|
||||
free(pIpForwardTable);
|
||||
|
||||
for (DWORD i = 0; i < table->dwNumEntries; i++) {
|
||||
auto &row = table->table[i];
|
||||
if (row.dwIndex == best && is_valid_ipaddr_row(row)) {
|
||||
return &row;
|
||||
}
|
||||
}
|
||||
|
||||
// last resort: keep a deterministic valid row instead of exposing all adapters
|
||||
for (DWORD i = 0; i < table->dwNumEntries; i++) {
|
||||
auto &row = table->table[i];
|
||||
if (is_valid_ipaddr_row(row)) {
|
||||
return &row;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void keep_only_ipaddr_row(PMIB_IPADDRTABLE table, MIB_IPADDRROW *row) {
|
||||
if (table == nullptr || row == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetIpAddrTable_log) {
|
||||
in_addr addr {};
|
||||
addr.s_addr = row->dwAddr;
|
||||
log_info("network", "Using preferred IP address row: {}", inet_ntoa(addr));
|
||||
}
|
||||
|
||||
table->table[0] = *row;
|
||||
table->dwNumEntries = 1;
|
||||
GetIpAddrTable_log = false;
|
||||
}
|
||||
|
||||
static ULONG WINAPI GetAdaptersInfo_hook(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen) {
|
||||
|
||||
// call orig
|
||||
@@ -183,6 +260,50 @@ static ULONG WINAPI GetAdaptersInfo_hook(PIP_ADAPTER_INFO pAdapterInfo, PULONG p
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DWORD WINAPI GetIpAddrTable_hook(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder) {
|
||||
|
||||
auto input_size = pdwSize != nullptr ? *pdwSize : 0;
|
||||
auto ret = GetIpAddrTable_orig(pIpAddrTable, pdwSize, bOrder);
|
||||
|
||||
if (ret == NO_ERROR) {
|
||||
auto row = find_preferred_ipaddr_row(pIpAddrTable);
|
||||
if (row != nullptr) {
|
||||
keep_only_ipaddr_row(pIpAddrTable, row);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret != ERROR_INSUFFICIENT_BUFFER || pIpAddrTable == nullptr || pdwSize == nullptr) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// If the caller's buffer is large enough for the filtered single-row table,
|
||||
// satisfy the call even when Windows needed more room for all adapters.
|
||||
const auto one_row_size = offsetof(MIB_IPADDRTABLE, table) + sizeof(MIB_IPADDRROW);
|
||||
if (input_size < one_row_size) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto full_size = *pdwSize;
|
||||
auto table = (PMIB_IPADDRTABLE) malloc(full_size);
|
||||
if (table == nullptr) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto full_ret = GetIpAddrTable_orig(table, &full_size, bOrder);
|
||||
if (full_ret == NO_ERROR) {
|
||||
auto row = find_preferred_ipaddr_row(table);
|
||||
if (row != nullptr) {
|
||||
keep_only_ipaddr_row(pIpAddrTable, row);
|
||||
*pdwSize = one_row_size;
|
||||
ret = NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
free(table);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int WINAPI bind_hook(SOCKET s, const struct sockaddr *name, int namelen) {
|
||||
|
||||
#ifdef __clang__
|
||||
@@ -243,6 +364,15 @@ void networkhook_init() {
|
||||
GetAdaptersInfo_orig = orig_addr;
|
||||
}
|
||||
|
||||
// GetIpAddrTable hook
|
||||
auto ip_addr_table_orig_addr = detour::iat_try(
|
||||
"GetIpAddrTable", GetIpAddrTable_hook, nullptr);
|
||||
if (!ip_addr_table_orig_addr) {
|
||||
log_warning("network", "Could not hook GetIpAddrTable");
|
||||
} else if (GetIpAddrTable_orig == nullptr) {
|
||||
GetIpAddrTable_orig = ip_addr_table_orig_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bind Hook
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user