mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-10-03 00:38:14 -07:00
network: NIC spoof matching tunnel (#912)
## Link to GitHub Issue or related Pull Request, if one exists #911 ## Description of change Add tunnelhost/tunnelclient modes to -nicspoof so two cabs can do LAN-style BPL matching over a real UDP path (including Wine), while keeping the fake overlay NIC. Offline spoof remains available as before. ## Testing DDR
This commit is contained in:
+131
-32
@@ -14,26 +14,32 @@
|
||||
|
||||
#include "util/detour.h"
|
||||
#include "util/logging.h"
|
||||
#include "hooks/nicspoof_tunnel.h"
|
||||
|
||||
namespace {
|
||||
constexpr uint32_t k_local_ip = 0x0A390302u; /* 10.57.3.2 */
|
||||
constexpr uint32_t k_gateway = 0x0A390301u; /* 10.57.3.1 */
|
||||
constexpr uint32_t k_dns = 0x0A390301u; /* 10.57.3.1 */
|
||||
constexpr uint32_t k_dhcp = 0x0A390301u; /* 10.57.3.1 */
|
||||
constexpr uint32_t k_mask = 0xFFFFFF00u; /* 255.255.255.0 */
|
||||
constexpr uint32_t k_subnet = 0x0A390300u;
|
||||
constexpr int k_prefix_len = 24;
|
||||
namespace nicspoof_detail {
|
||||
NicSpoofConfig g_cfg;
|
||||
|
||||
constexpr uint32_t k_default_local_ip = 0x0A64640Au; /* 10.100.100.10 */
|
||||
constexpr uint32_t k_gateway = 0x0A646401u; /* 10.100.100.1 */
|
||||
constexpr uint32_t k_dns1 = 0x0A02010Au; /* 10.2.1.10 */
|
||||
constexpr uint32_t k_dns2 = 0x0A02011Eu; /* 10.2.1.30 */
|
||||
constexpr uint32_t k_dhcp = 0xC0A80001u; /* 192.168.0.1 */
|
||||
constexpr uint32_t k_mask = 0xFF000000u; /* 255.0.0.0 */
|
||||
constexpr int k_prefix_len = 8;
|
||||
constexpr DWORD k_ifindex = 77;
|
||||
constexpr uint8_t k_fake_mac[6] = {0x12, 0x37, 0x13, 0x37, 0x13, 0x37};
|
||||
constexpr char k_hostname[] = "N1CSP00F";
|
||||
constexpr char k_domain[] = "local";
|
||||
constexpr char k_hostname_fqdn[] = "N1CSP00F.local";
|
||||
constexpr wchar_t k_domain_w[] = L"local";
|
||||
constexpr char k_hostname[] = "N1C5P00F";
|
||||
constexpr char k_domain[] = "sp2x";
|
||||
constexpr char k_hostname_fqdn[] = "N1C5P00F.sp2x";
|
||||
constexpr wchar_t k_domain_w[] = L"sp2x";
|
||||
constexpr char k_adapter_name[] = "{NICSPOOF-0880-0001-4250-4E6963537066}";
|
||||
constexpr char k_adapter_desc[] = "NicSpoof Virtual Ethernet";
|
||||
constexpr wchar_t k_friendly_name[] = L"NicSpoof";
|
||||
constexpr wchar_t k_adapter_desc_w[] = L"NicSpoof Virtual Ethernet";
|
||||
|
||||
uint32_t g_local_ip = k_default_local_ip;
|
||||
uint32_t g_subnet = k_default_local_ip & k_mask;
|
||||
|
||||
#define ALIGN_UP_PTR(p, a) \
|
||||
((BYTE *)(((ULONG_PTR)(p) + ((ULONG_PTR)(a) - 1)) & ~((ULONG_PTR)(a) - 1)))
|
||||
|
||||
@@ -125,7 +131,7 @@ DWORD WINAPI GetAdaptersInfo_hook(PIP_ADAPTER_INFO p, PULONG s) {
|
||||
memcpy(p->Address, k_fake_mac, 6);
|
||||
p->Type = MIB_IF_TYPE_ETHERNET;
|
||||
p->DhcpEnabled = 1;
|
||||
ip_to_str(k_local_ip, ip, sizeof(ip));
|
||||
ip_to_str(g_local_ip, ip, sizeof(ip));
|
||||
ip_to_str(k_gateway, gw, sizeof(gw));
|
||||
ip_to_str(k_dhcp, dhcp, sizeof(dhcp));
|
||||
strcpy(p->IpAddressList.IpAddress.String, ip);
|
||||
@@ -151,8 +157,11 @@ DWORD WINAPI GetAdaptersInfo_hook(PIP_ADAPTER_INFO p, PULONG s) {
|
||||
}
|
||||
|
||||
DWORD WINAPI GetNetworkParams_hook(PFIXED_INFO p, PULONG s) {
|
||||
ULONG need = static_cast<ULONG>(sizeof(FIXED_INFO));
|
||||
char dns[16];
|
||||
/* FIXED_INFO embeds the first IP_ADDR_STRING; second follows in the buffer. */
|
||||
ULONG need = static_cast<ULONG>(sizeof(FIXED_INFO) + sizeof(IP_ADDR_STRING));
|
||||
char dns1[16];
|
||||
char dns2[16];
|
||||
PIP_ADDR_STRING dns_second = nullptr;
|
||||
|
||||
if (!s) {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
@@ -164,18 +173,27 @@ DWORD WINAPI GetNetworkParams_hook(PFIXED_INFO p, PULONG s) {
|
||||
memset(p, 0, need);
|
||||
strncpy(p->HostName, k_hostname, sizeof(p->HostName) - 1);
|
||||
strncpy(p->DomainName, k_domain, sizeof(p->DomainName) - 1);
|
||||
ip_to_str(k_dns, dns, sizeof(dns));
|
||||
strcpy(p->DnsServerList.IpAddress.String, dns);
|
||||
ip_to_str(k_dns1, dns1, sizeof(dns1));
|
||||
ip_to_str(k_dns2, dns2, sizeof(dns2));
|
||||
strcpy(p->DnsServerList.IpAddress.String, dns1);
|
||||
p->DnsServerList.IpMask.String[0] = 0;
|
||||
p->DnsServerList.Context = 0;
|
||||
p->DnsServerList.Next = nullptr;
|
||||
dns_second = reinterpret_cast<PIP_ADDR_STRING>(
|
||||
reinterpret_cast<BYTE *>(p) + sizeof(FIXED_INFO));
|
||||
memset(dns_second, 0, sizeof(*dns_second));
|
||||
strcpy(dns_second->IpAddress.String, dns2);
|
||||
dns_second->IpMask.String[0] = 0;
|
||||
dns_second->Context = 0;
|
||||
dns_second->Next = nullptr;
|
||||
p->DnsServerList.Next = dns_second;
|
||||
p->CurrentDnsServer = &p->DnsServerList;
|
||||
p->NodeType = 1;
|
||||
p->EnableDns = 1;
|
||||
*s = need;
|
||||
if (g_log_params) {
|
||||
log_misc("network", "NIC spoof GetNetworkParams host={} domain={} dns={}",
|
||||
k_hostname, k_domain, dns);
|
||||
log_misc("network",
|
||||
"NIC spoof GetNetworkParams host={} domain={} dns={} dns2={}",
|
||||
k_hostname, k_domain, dns1, dns2);
|
||||
g_log_params = false;
|
||||
}
|
||||
return ERROR_SUCCESS;
|
||||
@@ -197,19 +215,21 @@ ULONG WINAPI GetAdaptersAddresses_hook(
|
||||
sizeof(void *) * 8 +
|
||||
sizeof(IP_ADAPTER_UNICAST_ADDRESS) +
|
||||
sizeof(IP_ADAPTER_PREFIX) +
|
||||
sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) +
|
||||
sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) * 2 +
|
||||
sizeof(IP_ADAPTER_GATEWAY_ADDRESS) +
|
||||
sizeof(sockaddr_in) * 4 + 64);
|
||||
sizeof(sockaddr_in) * 5 + 64);
|
||||
BYTE *blob = nullptr;
|
||||
PIP_ADAPTER_ADDRESSES a = nullptr;
|
||||
PIP_ADAPTER_UNICAST_ADDRESS u = nullptr;
|
||||
PIP_ADAPTER_PREFIX pref = nullptr;
|
||||
PIP_ADAPTER_GATEWAY_ADDRESS gw = nullptr;
|
||||
PIP_ADAPTER_DNS_SERVER_ADDRESS dns = nullptr;
|
||||
PIP_ADAPTER_DNS_SERVER_ADDRESS dns2 = nullptr;
|
||||
sockaddr_in *sa = nullptr;
|
||||
sockaddr_in *sm = nullptr;
|
||||
sockaddr_in *sg = nullptr;
|
||||
sockaddr_in *ds = nullptr;
|
||||
sockaddr_in *ds2 = nullptr;
|
||||
|
||||
(void)Reserved;
|
||||
(void)Flags;
|
||||
@@ -267,7 +287,7 @@ ULONG WINAPI GetAdaptersAddresses_hook(
|
||||
blob += sizeof(*sa);
|
||||
memset(sa, 0, sizeof(*sa));
|
||||
sa->sin_family = AF_INET;
|
||||
sa->sin_addr.s_addr = htonl(k_local_ip);
|
||||
sa->sin_addr.s_addr = htonl(g_local_ip);
|
||||
u->Address.lpSockaddr = reinterpret_cast<LPSOCKADDR>(sa);
|
||||
u->Address.iSockaddrLength = sizeof(*sa);
|
||||
a->FirstUnicastAddress = u;
|
||||
@@ -282,7 +302,7 @@ ULONG WINAPI GetAdaptersAddresses_hook(
|
||||
blob += sizeof(*sm);
|
||||
memset(sm, 0, sizeof(*sm));
|
||||
sm->sin_family = AF_INET;
|
||||
sm->sin_addr.s_addr = htonl(k_subnet);
|
||||
sm->sin_addr.s_addr = htonl(g_subnet);
|
||||
pref->Address.lpSockaddr = reinterpret_cast<LPSOCKADDR>(sm);
|
||||
pref->Address.iSockaddrLength = sizeof(*sm);
|
||||
a->FirstPrefix = pref;
|
||||
@@ -309,10 +329,23 @@ ULONG WINAPI GetAdaptersAddresses_hook(
|
||||
blob += sizeof(*ds);
|
||||
memset(ds, 0, sizeof(*ds));
|
||||
ds->sin_family = AF_INET;
|
||||
ds->sin_addr.s_addr = htonl(k_dns);
|
||||
ds->sin_addr.s_addr = htonl(k_dns1);
|
||||
dns->Address.lpSockaddr = reinterpret_cast<LPSOCKADDR>(ds);
|
||||
dns->Address.iSockaddrLength = sizeof(*ds);
|
||||
dns->Next = nullptr;
|
||||
|
||||
blob = ALIGN_UP_PTR(blob, sizeof(void *));
|
||||
dns2 = reinterpret_cast<PIP_ADAPTER_DNS_SERVER_ADDRESS>(blob);
|
||||
blob += sizeof(*dns2);
|
||||
memset(dns2, 0, sizeof(*dns2));
|
||||
ds2 = reinterpret_cast<sockaddr_in *>(blob);
|
||||
blob += sizeof(*ds2);
|
||||
memset(ds2, 0, sizeof(*ds2));
|
||||
ds2->sin_family = AF_INET;
|
||||
ds2->sin_addr.s_addr = htonl(k_dns2);
|
||||
dns2->Address.lpSockaddr = reinterpret_cast<LPSOCKADDR>(ds2);
|
||||
dns2->Address.iSockaddrLength = sizeof(*ds2);
|
||||
dns2->Next = nullptr;
|
||||
dns->Next = dns2;
|
||||
a->FirstDnsServerAddress = dns;
|
||||
|
||||
a->Next = nullptr;
|
||||
@@ -404,7 +437,7 @@ INT WSAAPI getaddrinfo_hook(
|
||||
if (!pNodeName || !pNodeName[0] || name_is_local(pNodeName)) {
|
||||
if (pNodeName && (_stricmp(pNodeName, k_hostname) == 0 ||
|
||||
_stricmp(pNodeName, k_hostname_fqdn) == 0)) {
|
||||
ip = k_local_ip;
|
||||
ip = g_local_ip;
|
||||
} else {
|
||||
ip = 0x7F000001u;
|
||||
}
|
||||
@@ -412,7 +445,7 @@ INT WSAAPI getaddrinfo_hook(
|
||||
ip = parse_ipv4(pNodeName);
|
||||
} else {
|
||||
/* offline=1: map external names to local_ip */
|
||||
ip = k_local_ip;
|
||||
ip = g_local_ip;
|
||||
}
|
||||
|
||||
if (pServiceName && pServiceName[0]) {
|
||||
@@ -471,7 +504,7 @@ void install_nicspoof_hooks() {
|
||||
char ipstr[16];
|
||||
char maskstr[16];
|
||||
char gwstr[16];
|
||||
ip_to_str(k_local_ip, ipstr, sizeof(ipstr));
|
||||
ip_to_str(g_local_ip, ipstr, sizeof(ipstr));
|
||||
ip_to_str(k_mask, maskstr, sizeof(maskstr));
|
||||
ip_to_str(k_gateway, gwstr, sizeof(gwstr));
|
||||
log_info("network",
|
||||
@@ -508,7 +541,6 @@ void install_nicspoof_hooks() {
|
||||
(void *) freeaddrinfo_hook,
|
||||
(void **) &freeaddrinfo_orig);
|
||||
|
||||
/* FreeAddrInfoA is often the same address; only hook if distinct. */
|
||||
{
|
||||
HMODULE ws = GetModuleHandleA("ws2_32.dll");
|
||||
void *faa = nullptr;
|
||||
@@ -539,8 +571,75 @@ void install_nicspoof_hooks() {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
bool ip_in_overlay_range(uint32_t ip) {
|
||||
const uint32_t net = k_gateway & k_mask;
|
||||
const uint32_t bcast = net | ~k_mask;
|
||||
if ((ip & k_mask) != net) {
|
||||
return false;
|
||||
}
|
||||
if (ip == net || ip == bcast || ip == k_gateway ||
|
||||
ip == k_dns1 || ip == k_dns2) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void init_impl() {
|
||||
if (g_cfg.mode == NicSpoofMode::Off) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_local_ip = g_cfg.local_ip ? g_cfg.local_ip : k_default_local_ip;
|
||||
if (!ip_in_overlay_range(g_local_ip)) {
|
||||
char bad[16];
|
||||
ip_to_str(g_local_ip, bad, sizeof(bad));
|
||||
log_warning("network",
|
||||
"NIC spoof: IP {} is outside 10.0.0.0/8 usable range; "
|
||||
"using 10.100.100.10",
|
||||
bad);
|
||||
g_local_ip = k_default_local_ip;
|
||||
}
|
||||
g_subnet = g_local_ip & k_mask;
|
||||
|
||||
const char *mode_str = "offline";
|
||||
if (g_cfg.mode == NicSpoofMode::TunnelHost) {
|
||||
mode_str = "tunnelhost";
|
||||
} else if (g_cfg.mode == NicSpoofMode::TunnelClient) {
|
||||
mode_str = "tunnelclient";
|
||||
}
|
||||
log_info("network", "NIC spoof mode={}", mode_str);
|
||||
|
||||
install_nicspoof_hooks();
|
||||
|
||||
if (g_cfg.mode == NicSpoofMode::TunnelHost ||
|
||||
g_cfg.mode == NicSpoofMode::TunnelClient) {
|
||||
nicspoof_tunnel_init(g_cfg);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nicspoof_detail
|
||||
|
||||
void nicspoof_configure(const NicSpoofConfig &cfg) {
|
||||
nicspoof_detail::g_cfg = cfg;
|
||||
}
|
||||
|
||||
bool nicspoof_tunnel_enabled() {
|
||||
return nicspoof_detail::g_cfg.mode == NicSpoofMode::TunnelHost ||
|
||||
nicspoof_detail::g_cfg.mode == NicSpoofMode::TunnelClient;
|
||||
}
|
||||
|
||||
uint32_t nicspoof_local_ip() {
|
||||
return nicspoof_detail::g_local_ip;
|
||||
}
|
||||
|
||||
uint32_t nicspoof_mask() {
|
||||
return nicspoof_detail::k_mask;
|
||||
}
|
||||
|
||||
uint32_t nicspoof_subnet() {
|
||||
return nicspoof_detail::g_subnet;
|
||||
}
|
||||
|
||||
void nicspoof_init() {
|
||||
install_nicspoof_hooks();
|
||||
nicspoof_detail::init_impl();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user