mirror of
https://gitea.tendokyu.moe/Hay1tsme/segatools.git
synced 2026-05-06 21:38:58 -05:00
This adds full support for the Taisen series of games, namely Sangokushi Taisen and Eiketsu Taisen. Games added: * Sangokushi Taisen (SDDD) * Eiketsu Taisen (SDGY) Devices added: * CHC-320 printer (SGT) * "Printer camera" (SGT, unsure what this actually really is) * CX-7000 printer (EKT) * Y3CR BD SIE F720MM (SGT, EKT) Notable changes in the codebase: * Renamed everything printer specific to seperate between CHC and CX. * Many new function and registry hooks were added across the board. * An error is now logged when segatools.ini (or the path in `SEGATOOLS_CONFIG_PATH`) cannot be found. * Netenv now redirects UDP broadcasts targeted at the subnet that is specified in the keychip configuration. The terminal announces it's presence by broadcasting UDP to 192.168.189.255, this will be redirected to 255.255.255.255. * Vfs now seperates between absolute and relative paths in `vfs_fixup_path` via an environment variable called `SEGATOOLS_VFS_RELATIVE_PATH`. This is needed because amcapture accesses files as workingdirectory-relative. * The Y3 board emulation has support for external Y3 I/O dlls. The default implementation (y3ws) that comes with this is a websocket implementation. The docs are available under `doc\y3ws.txt` and a sample card player .html file is under `dist\ekt\card_player.html`. I already know one person that is hosting a massively improved version of it. * For websockets, my own websocket implementation is used as a subproject (MIT license): https://github.com/akechi-haruka/cwinwebsocket * For JSON, cJSON was embedded (MIT license): https://github.com/DaveGamble/cJSON * y3ws reads all printed cards from `DEVICE\print` by default including card back sides. It's up to the client to merge or skip them. Remarks: * SGT takes ~8 minutes to load. This seems to be intentional. * SGT uses some weird TCP network implementation like IDZ. I have not bothered reversing that yet and I have confirmed everything working from the test menu. * EKT will throw a network error if no terminal is found. You must run the terminal on another computer to be able to launch the satellite. * EKT has a very bizzare speed glitch that will speed up the ingame unit movement by several 1000% and also slows down cutscene animations by 90%. When this effect is active, you also take a ton more damage than usual. I do not know what causes this and it seems PC specific. * EKT is very stutter sensitive and will throw error 6401 (I/O timeout) at random when trying to alt+tab or have other things running. * EKT features a livestream system called Enbu (or "Dojo Upload"). While you are in a match, regardless of vs. AI or another player, the game will record your screen and live-stream it to the Enbu server as defined by the game server's startup response. The application responsible for that, "AM Capture" will not limit it's recording to the game window, but also anything that overlays the game window (notifications, popups, alt+tabbed windows, web browsers, etc). Since this is live-streamed, killing the process will have no effect afterwards, as the frames showing unwanted things will already have been transmitted. To make people aware of this, a one-time dialog message will pop up when starting EKT. The flag for that is stored in the DEVICE folder. Closes #25. Co-authored-by: Dniel97 <Dniel97@noreply.gitea.tendokyu.moe> Reviewed-on: https://gitea.tendokyu.moe/TeamTofuShop/segatools/pulls/85 Co-authored-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Co-committed-by: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com>
590 lines
17 KiB
C
590 lines
17 KiB
C
#include <windows.h>
|
|
#include <winsock2.h>
|
|
#include <iphlpapi.h>
|
|
#include <iptypes.h>
|
|
#include <winternl.h>
|
|
#include <assert.h>
|
|
#include <icmpapi.h>
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include "hook/table.h"
|
|
|
|
#include "platform/netenv.h"
|
|
|
|
#include "hook/procaddr.h"
|
|
#include "platform/nusec.h"
|
|
|
|
#include "util/dprintf.h"
|
|
|
|
struct netenv {
|
|
IP_ADAPTER_ADDRESSES head;
|
|
char name[64];
|
|
wchar_t dns_suffix[64];
|
|
wchar_t description[64];
|
|
wchar_t friendly_name[64];
|
|
IP_ADAPTER_PREFIX prefix;
|
|
IP_ADAPTER_UNICAST_ADDRESS iface;
|
|
IP_ADAPTER_GATEWAY_ADDRESS router;
|
|
IP_ADAPTER_DNS_SERVER_ADDRESS dns;
|
|
struct sockaddr_in prefix_sa;
|
|
struct sockaddr_in iface_sa;
|
|
struct sockaddr_in router_sa;
|
|
struct sockaddr_in dns_sa;
|
|
};
|
|
|
|
/* Hook functions */
|
|
|
|
static uint32_t WINAPI hook_GetAdaptersAddresses(
|
|
uint32_t Family,
|
|
uint32_t Flags,
|
|
void *Reserved,
|
|
IP_ADAPTER_ADDRESSES *AdapterAddresses,
|
|
uint32_t *SizePointer);
|
|
|
|
static uint32_t WINAPI hook_GetAdaptersInfo(
|
|
IP_ADAPTER_INFO *AdapterInfo,
|
|
uint32_t *SizePointer);
|
|
|
|
static uint32_t WINAPI hook_GetBestRoute(
|
|
uint32_t src_ip,
|
|
uint32_t dest_ip,
|
|
MIB_IPFORWARDROW *route);
|
|
|
|
static uint32_t WINAPI hook_GetIfTable(
|
|
MIB_IFTABLE *pIfTable,
|
|
uint32_t *pdwSize,
|
|
BOOL bOrder);
|
|
|
|
static uint32_t WINAPI hook_IcmpSendEcho2(
|
|
HANDLE IcmpHandle,
|
|
HANDLE Event,
|
|
PIO_APC_ROUTINE ApcRoutine,
|
|
void *ApcContext,
|
|
uint32_t DestinationAddress,
|
|
void *RequestData,
|
|
uint16_t RequestSize,
|
|
IP_OPTION_INFORMATION *RequestOptions,
|
|
void *ReplyBuffer,
|
|
uint32_t ReplySize,
|
|
uint32_t Timeout);
|
|
|
|
static int WINAPI hook_sendto(
|
|
SOCKET s,
|
|
const char* buf,
|
|
int len,
|
|
int flags,
|
|
const struct sockaddr *to,
|
|
int tolen);
|
|
|
|
/* Link pointers */
|
|
|
|
static uint32_t (WINAPI *next_GetAdaptersAddresses)(
|
|
uint32_t Family,
|
|
uint32_t Flags,
|
|
void *Reserved,
|
|
IP_ADAPTER_ADDRESSES *AdapterAddresses,
|
|
uint32_t *SizePointer);
|
|
|
|
static uint32_t (WINAPI *next_GetAdaptersInfo)(
|
|
IP_ADAPTER_INFO *AdapterInfo,
|
|
uint32_t *SizePointer);
|
|
|
|
static uint32_t (WINAPI *next_GetBestRoute)(
|
|
uint32_t src_ip,
|
|
uint32_t dest_ip,
|
|
MIB_IPFORWARDROW *route);
|
|
|
|
static uint32_t (WINAPI *next_GetIfTable)(
|
|
MIB_IFTABLE *pIfTable,
|
|
uint32_t *pdwSize,
|
|
BOOL bOrder);
|
|
|
|
static uint32_t (WINAPI *next_IcmpSendEcho2)(
|
|
HANDLE IcmpHandle,
|
|
HANDLE Event,
|
|
PIO_APC_ROUTINE ApcRoutine,
|
|
void *ApcContext,
|
|
uint32_t DestinationAddress,
|
|
void *RequestData,
|
|
uint16_t RequestSize,
|
|
IP_OPTION_INFORMATION *RequestOptions,
|
|
void *ReplyBuffer,
|
|
uint32_t ReplySize,
|
|
uint32_t Timeout);
|
|
|
|
static int (WINAPI *next_sendto)(
|
|
SOCKET s,
|
|
const char *buf,
|
|
int len,
|
|
int flags,
|
|
const struct sockaddr *to,
|
|
int tolen);
|
|
|
|
|
|
static const struct hook_symbol netenv_hook_syms[] = {
|
|
{
|
|
.name = "GetAdaptersAddresses",
|
|
.patch = hook_GetAdaptersAddresses,
|
|
.link = (void **) &next_GetAdaptersAddresses,
|
|
}, {
|
|
.name = "GetAdaptersInfo",
|
|
.patch = hook_GetAdaptersInfo,
|
|
.link = (void **) &next_GetAdaptersInfo,
|
|
}, {
|
|
.name = "GetBestRoute",
|
|
.patch = hook_GetBestRoute,
|
|
.link = (void **) &next_GetBestRoute,
|
|
}, {
|
|
.name = "GetIfTable",
|
|
.patch = hook_GetIfTable,
|
|
.link = (void **) &next_GetIfTable,
|
|
}, {
|
|
.name = "IcmpSendEcho2",
|
|
.patch = hook_IcmpSendEcho2,
|
|
.link = (void **) &next_IcmpSendEcho2,
|
|
}
|
|
};
|
|
|
|
static struct hook_symbol netenv_hook_syms_ws2[] = {
|
|
{
|
|
.name = "sendto",
|
|
.patch = hook_sendto,
|
|
.ordinal = 20,
|
|
.link = (void **) &next_sendto
|
|
},
|
|
};
|
|
|
|
static uint32_t netenv_ip_prefix;
|
|
static uint32_t netenv_ip_bcast;
|
|
static uint32_t netenv_ip_iface;
|
|
static uint32_t netenv_ip_router;
|
|
static uint8_t netenv_mac_addr[6];
|
|
|
|
HRESULT netenv_hook_init(
|
|
const struct netenv_config *cfg,
|
|
const struct nusec_config *kc_cfg)
|
|
{
|
|
assert(cfg != NULL);
|
|
assert(kc_cfg != NULL);
|
|
|
|
if (!cfg->enable) {
|
|
return S_FALSE;
|
|
}
|
|
|
|
if (!kc_cfg->enable) {
|
|
dprintf("Netenv: Keychip emu is off? Disabling Netenv emu.\n");
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
netenv_ip_prefix = kc_cfg->subnet;
|
|
netenv_ip_bcast = kc_cfg->bcast;
|
|
netenv_ip_iface = kc_cfg->subnet | cfg->addr_suffix;
|
|
netenv_ip_router = kc_cfg->subnet | cfg->router_suffix;
|
|
memcpy(netenv_mac_addr, cfg->mac_addr, sizeof(netenv_mac_addr));
|
|
|
|
netenv_hook_apply_hooks(NULL);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void netenv_hook_apply_hooks(HMODULE mod) {
|
|
hook_table_apply(
|
|
mod,
|
|
"iphlpapi.dll",
|
|
netenv_hook_syms,
|
|
_countof(netenv_hook_syms));
|
|
|
|
hook_table_apply(
|
|
mod,
|
|
"ws2_32.dll",
|
|
netenv_hook_syms_ws2,
|
|
_countof(netenv_hook_syms_ws2));
|
|
|
|
proc_addr_table_push(
|
|
mod,
|
|
"ws2_32.dll",
|
|
netenv_hook_syms_ws2,
|
|
_countof(netenv_hook_syms_ws2));
|
|
}
|
|
|
|
static uint32_t WINAPI hook_GetAdaptersAddresses(
|
|
uint32_t Family,
|
|
uint32_t Flags,
|
|
void *Reserved,
|
|
IP_ADAPTER_ADDRESSES *AdapterAddresses,
|
|
uint32_t *SizePointer)
|
|
{
|
|
/* This hook errs on the side of caution and returns a lot more
|
|
information than the ALLNET lib cares about. MSVC mangles the main
|
|
call site for this API quite aggressively, so by the time we decompile
|
|
the code in question it's a little difficult to tell which pieces the
|
|
ALLNET lib pays attention to. */
|
|
|
|
uint32_t nbytes;
|
|
struct netenv *env;
|
|
|
|
if (Reserved != NULL || SizePointer == NULL) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
nbytes = *SizePointer;
|
|
*SizePointer = sizeof(*env);
|
|
|
|
if (AdapterAddresses == NULL || nbytes < sizeof(*env)) {
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
env = CONTAINING_RECORD(AdapterAddresses, struct netenv, head);
|
|
memset(env, 0, sizeof(*env));
|
|
|
|
env->head.Length = sizeof(env->head);
|
|
env->head.IfIndex = 1;
|
|
env->head.AdapterName = env->name;
|
|
env->head.FirstUnicastAddress = &env->iface;
|
|
env->head.FirstDnsServerAddress = &env->dns;
|
|
env->head.DnsSuffix = env->dns_suffix;
|
|
env->head.Description = env->description;
|
|
env->head.FriendlyName = env->friendly_name;
|
|
memcpy( env->head.PhysicalAddress,
|
|
netenv_mac_addr,
|
|
sizeof(netenv_mac_addr));
|
|
env->head.PhysicalAddressLength = sizeof(netenv_mac_addr);
|
|
env->head.Flags = IP_ADAPTER_DHCP_ENABLED | IP_ADAPTER_IPV4_ENABLED;
|
|
env->head.Mtu = 4200; /* idk what's typical here */
|
|
env->head.IfType = IF_TYPE_ETHERNET_CSMACD;
|
|
env->head.OperStatus = IfOperStatusUp;
|
|
env->head.FirstPrefix = &env->prefix;
|
|
env->head.FirstGatewayAddress = &env->router;
|
|
|
|
strcpy_s(
|
|
env->name,
|
|
_countof(env->name),
|
|
"{00000000-0000-0000-0000-000000000000}");
|
|
|
|
wcscpy_s(
|
|
env->dns_suffix,
|
|
_countof(env->dns_suffix),
|
|
L"local");
|
|
|
|
wcscpy_s(
|
|
env->description,
|
|
_countof(env->description),
|
|
L"Interface Description");
|
|
|
|
wcscpy_s(
|
|
env->friendly_name,
|
|
_countof(env->friendly_name),
|
|
L"Fake Ethernet");
|
|
|
|
env->iface.Length = sizeof(env->iface);
|
|
env->iface.Flags = 0;
|
|
env->iface.Address.lpSockaddr = (struct sockaddr *) &env->iface_sa;
|
|
env->iface.Address.iSockaddrLength = sizeof(env->iface_sa);
|
|
env->iface.PrefixOrigin = IpPrefixOriginDhcp;
|
|
env->iface.SuffixOrigin = IpSuffixOriginDhcp;
|
|
env->iface.DadState = IpDadStatePreferred;
|
|
env->iface.ValidLifetime = UINT32_MAX;
|
|
env->iface.PreferredLifetime = UINT32_MAX;
|
|
env->iface.LeaseLifetime = 86400;
|
|
env->iface.OnLinkPrefixLength = 24;
|
|
|
|
env->prefix.Length = sizeof(env->prefix);
|
|
env->prefix.Address.lpSockaddr = (struct sockaddr *) &env->prefix_sa;
|
|
env->prefix.Address.iSockaddrLength = sizeof(env->prefix_sa);
|
|
env->prefix.PrefixLength = 24;
|
|
|
|
env->router.Length = sizeof(env->router);
|
|
env->router.Address.lpSockaddr = (struct sockaddr *) &env->router_sa;
|
|
env->router.Address.iSockaddrLength = sizeof(env->router_sa);
|
|
|
|
env->dns.Length = sizeof(env->dns);
|
|
env->dns.Address.lpSockaddr = (struct sockaddr *) &env->dns_sa;
|
|
env->dns.Address.iSockaddrLength = sizeof(env->dns_sa);
|
|
|
|
env->prefix_sa.sin_family = AF_INET;
|
|
env->prefix_sa.sin_addr.s_addr = _byteswap_ulong(netenv_ip_prefix);
|
|
|
|
env->iface_sa.sin_family = AF_INET;
|
|
env->iface_sa.sin_addr.s_addr = _byteswap_ulong(netenv_ip_iface);
|
|
|
|
env->router_sa.sin_family = AF_INET;
|
|
env->router_sa.sin_addr.s_addr = _byteswap_ulong(netenv_ip_router);
|
|
|
|
env->dns_sa.sin_family = AF_INET;
|
|
env->dns_sa.sin_addr.s_addr = _byteswap_ulong(netenv_ip_router);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
static uint32_t WINAPI hook_GetAdaptersInfo(
|
|
IP_ADAPTER_INFO *ai,
|
|
uint32_t *nbytes_inout)
|
|
{
|
|
IP_ADDR_STRING iface;
|
|
IP_ADDR_STRING router;
|
|
uint32_t nbytes;
|
|
|
|
if (nbytes_inout == NULL) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
nbytes = *nbytes_inout;
|
|
*nbytes_inout = sizeof(*ai);
|
|
|
|
if (ai == NULL || nbytes < sizeof(*ai)) {
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
dprintf("Netenv: GetAdaptersInfo: Virtualized LAN configuration:\n");
|
|
dprintf("Netenv: Interface IP : %3i.%3i.%3i.%3i\n",
|
|
(uint8_t) (netenv_ip_iface >> 24),
|
|
(uint8_t) (netenv_ip_iface >> 16),
|
|
(uint8_t) (netenv_ip_iface >> 8),
|
|
(uint8_t) (netenv_ip_iface ));
|
|
dprintf("Netenv: Router IP : %3i.%3i.%3i.%3i\n",
|
|
(uint8_t) (netenv_ip_router >> 24),
|
|
(uint8_t) (netenv_ip_router >> 16),
|
|
(uint8_t) (netenv_ip_router >> 8),
|
|
(uint8_t) (netenv_ip_router ));
|
|
dprintf("Netenv: MAC Address : %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
netenv_mac_addr[0],
|
|
netenv_mac_addr[1],
|
|
netenv_mac_addr[2],
|
|
netenv_mac_addr[3],
|
|
netenv_mac_addr[4],
|
|
netenv_mac_addr[5]);
|
|
|
|
memset(&iface, 0, sizeof(iface));
|
|
memset(&router, 0, sizeof(router));
|
|
|
|
sprintf_s(
|
|
iface.IpAddress.String,
|
|
_countof(iface.IpAddress.String),
|
|
"%i.%i.%i.%i",
|
|
(uint8_t) (netenv_ip_iface >> 24),
|
|
(uint8_t) (netenv_ip_iface >> 16),
|
|
(uint8_t) (netenv_ip_iface >> 8),
|
|
(uint8_t) (netenv_ip_iface ));
|
|
|
|
strcpy_s(
|
|
iface.IpMask.String,
|
|
_countof(iface.IpMask.String),
|
|
"255.255.255.0");
|
|
|
|
sprintf_s(
|
|
router.IpAddress.String,
|
|
_countof(iface.IpAddress.String),
|
|
"%i.%i.%i.%i",
|
|
(uint8_t) (netenv_ip_router >> 24),
|
|
(uint8_t) (netenv_ip_router >> 16),
|
|
(uint8_t) (netenv_ip_router >> 8),
|
|
(uint8_t) (netenv_ip_router ));
|
|
|
|
strcpy_s(
|
|
router.IpMask.String,
|
|
_countof(router.IpMask.String),
|
|
"255.255.255.0");
|
|
|
|
memset(ai, 0, sizeof(*ai));
|
|
strcpy_s(
|
|
ai->AdapterName,
|
|
_countof(ai->AdapterName),
|
|
"Fake Ethernet");
|
|
strcpy_s(ai->Description,
|
|
_countof(ai->Description),
|
|
"Adapter Description");
|
|
ai->AddressLength = sizeof(netenv_mac_addr);
|
|
memcpy(ai->Address, netenv_mac_addr, sizeof(netenv_mac_addr));
|
|
ai->Index = 1;
|
|
ai->Type = MIB_IF_TYPE_ETHERNET;
|
|
ai->DhcpEnabled = 1;
|
|
memcpy(&ai->IpAddressList, &iface, sizeof(iface));
|
|
memcpy(&ai->GatewayList, &router, sizeof(router));
|
|
memcpy(&ai->DhcpServer, &router, sizeof(router));
|
|
ai->LeaseObtained = time(NULL) - 3600;
|
|
ai->LeaseExpires = time(NULL) + 86400;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
static uint32_t WINAPI hook_GetBestRoute(
|
|
uint32_t src_ip,
|
|
uint32_t dest_ip,
|
|
MIB_IPFORWARDROW *route)
|
|
{
|
|
if (route == NULL) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
uint32_t src_addr = _byteswap_ulong(src_ip);
|
|
uint32_t dest_addr = _byteswap_ulong(dest_ip);
|
|
|
|
dprintf("Netenv: GetBestRoute ip4 %u.%u.%u.%u -> ip4 %u.%u.%u.%u\n",
|
|
(src_addr >> 24) & 0xff, (src_addr >> 16) & 0xff, (src_addr >> 8) & 0xff, src_addr & 0xff,
|
|
(dest_addr >> 24) & 0xff, (dest_addr >> 16) & 0xff, (dest_addr >> 8) & 0xff, dest_addr & 0xff);
|
|
|
|
memset(route, 0, sizeof(*route));
|
|
|
|
/* This doesn't seem to get read? It just needs to succeed. */
|
|
|
|
route->dwForwardDest = 0x00000000;
|
|
route->dwForwardMask = 0xFFFFFFFF;
|
|
route->dwForwardPolicy = 0; /* idk */
|
|
route->dwForwardNextHop = _byteswap_ulong(netenv_ip_router);
|
|
route->dwForwardIfIndex = 1;
|
|
route->dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
|
|
route->dwForwardProto = MIB_IPPROTO_NETMGMT;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
static uint32_t WINAPI hook_GetIfTable(
|
|
MIB_IFTABLE *pIfTable,
|
|
uint32_t *pdwSize,
|
|
BOOL bOrder)
|
|
{
|
|
MIB_IFROW *row;
|
|
uint32_t nbytes;
|
|
|
|
if (pdwSize == NULL) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
nbytes = *pdwSize;
|
|
*pdwSize = sizeof(*row) + sizeof(DWORD);
|
|
|
|
if (pIfTable == NULL || nbytes < sizeof(*row) + sizeof(DWORD)) {
|
|
return ERROR_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
pIfTable->dwNumEntries = 1;
|
|
|
|
row = pIfTable->table;
|
|
memset(row, 0, sizeof(*row));
|
|
|
|
wcscpy_s(row->wszName, _countof(row->wszName), L"Fake Ethernet");
|
|
row->dwIndex = 1; /* Should match other IF_INDEX fields we return */
|
|
row->dwType = IF_TYPE_ETHERNET_CSMACD;
|
|
row->dwMtu = 4200; /* I guess? */
|
|
row->dwSpeed = 1000000000;
|
|
row->dwPhysAddrLen = sizeof(netenv_mac_addr);
|
|
memcpy(row->bPhysAddr, netenv_mac_addr, sizeof(netenv_mac_addr));
|
|
row->dwAdminStatus = 1;
|
|
row->dwOperStatus = IF_OPER_STATUS_OPERATIONAL;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
static uint32_t WINAPI hook_IcmpSendEcho2(
|
|
HANDLE IcmpHandle,
|
|
HANDLE Event,
|
|
PIO_APC_ROUTINE ApcRoutine,
|
|
void *ApcContext,
|
|
uint32_t DestinationAddress,
|
|
void *RequestData,
|
|
uint16_t RequestSize,
|
|
IP_OPTION_INFORMATION *RequestOptions,
|
|
void *ReplyBuffer,
|
|
uint32_t ReplySize,
|
|
uint32_t Timeout)
|
|
{
|
|
ICMP_ECHO_REPLY *pong;
|
|
BOOL ok;
|
|
|
|
if (IcmpHandle == NULL || IcmpHandle == INVALID_HANDLE_VALUE) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (ApcRoutine != NULL) {
|
|
dprintf("%s: Got APC routine...\n", __func__);
|
|
SetLastError(ERROR_NOT_SUPPORTED);
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (ReplyBuffer == NULL) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (ReplySize < sizeof(ICMP_ECHO_REPLY)) {
|
|
SetLastError(IP_BUF_TOO_SMALL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint32_t addr = _byteswap_ulong(DestinationAddress);
|
|
|
|
dprintf("Netenv: Virtualized ICMP Ping to ip4 %u.%u.%u.%u\n",
|
|
(addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
|
|
|
|
pong = (ICMP_ECHO_REPLY *) ReplyBuffer;
|
|
memset(pong, 0, sizeof(*pong));
|
|
pong->Address = DestinationAddress;
|
|
pong->Status = IP_SUCCESS;
|
|
pong->RoundTripTime = 1;
|
|
pong->DataSize = 0;
|
|
pong->Reserved = 1; /* Number of ICMP_ECHO_REPLY structs in ReplyBuffer */
|
|
pong->Data = NULL;
|
|
|
|
if (Event != NULL) {
|
|
ok = SetEvent(Event);
|
|
|
|
if (ok) {
|
|
SetLastError(ERROR_IO_PENDING);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
dprintf("%s: Unexpected synchronous call...\n", __func__);
|
|
SetLastError(ERROR_SUCCESS);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int WINAPI hook_sendto(
|
|
SOCKET s,
|
|
const char* buf,
|
|
int len,
|
|
int flags,
|
|
const struct sockaddr* to,
|
|
int tolen) {
|
|
if (to->sa_family != AF_INET) {
|
|
// we only care about IP packets
|
|
return next_sendto(s, buf, len, flags, to, tolen);
|
|
}
|
|
|
|
const struct sockaddr_in* original_to = (struct sockaddr_in*)to;
|
|
|
|
uint32_t bc_addr = _byteswap_ulong(netenv_ip_prefix | 0xFF);
|
|
|
|
if (original_to->sin_addr.S_un.S_addr == bc_addr) {
|
|
|
|
uint32_t src_addr = _byteswap_ulong(original_to->sin_addr.S_un.S_addr);
|
|
uint32_t dest_addr = _byteswap_ulong(netenv_ip_bcast);
|
|
|
|
dprintf("Netenv: sendTo broadcast %u.%u.%u.%u -> %u.%u.%u.%u\n",
|
|
(src_addr >> 24) & 0xff, (src_addr >> 16) & 0xff, (src_addr >> 8) & 0xff, src_addr & 0xff,
|
|
(dest_addr >> 24) & 0xff, (dest_addr >> 16) & 0xff, (dest_addr >> 8) & 0xff, dest_addr & 0xff);
|
|
|
|
struct sockaddr_in modified_to = {0};
|
|
memcpy(&modified_to, original_to, tolen);
|
|
|
|
modified_to.sin_addr.S_un.S_addr = dest_addr;
|
|
|
|
return next_sendto(s, buf, len, flags, (struct sockaddr*)&modified_to, sizeof(modified_to));
|
|
}
|
|
|
|
return next_sendto(s, buf, len, flags, to, tolen);
|
|
} |