wip(hook): preserve local FIFA17 configurable-server redirect + hook refactors

Preserved uncommitted openfut-hook WIP from the feat/launcher-arming checkout so the
canonical launcher can move to the reconciled merge ca7ce26 without losing it. This is
WORK-IN-PROGRESS (not production-polished): a configurable OpenFUT-server redirect for the
injected hook — new src/server.rs (server::set / sin_addr / dest_port_nbo_from_source_nbo,
referenced by lib.rs + connect_hook + connectex_hook) plus supporting changes to config.rs,
connect_hook.rs, connectex_hook.rs, hooks.rs, iat.rs, lib.rs, origin_spy.rs, ssl_patch.rs,
tls_bypass.rs, Cargo.{toml,lock}.

NOTE: this overlaps (same files, different approach) the SBC-tracing lineage's openfut-hook
changes now merged in ca7ce26; reconciling the two hook variants is a separate, deliberate
task. This commit only PRESERVES the local WIP on a dedicated branch.
This commit is contained in:
funman300
2026-08-13 15:10:12 +00:00
parent 13339c1478
commit 4e44a3792f
12 changed files with 464 additions and 191 deletions
+35 -20
View File
@@ -1,22 +1,23 @@
use std::{
ffi::CStr,
sync::{
OnceLock,
atomic::{AtomicBool, Ordering},
OnceLock,
},
};
use windows_sys::Win32::Networking::WinSock::{ADDRINFOA, getaddrinfo as sys_getaddrinfo};
use windows_sys::Win32::Networking::WinSock::{getaddrinfo as sys_getaddrinfo, ADDRINFOA};
type GetaddrinfoFn = unsafe extern "system" fn(
*const u8,
*const u8,
*const ADDRINFOA,
*mut *mut ADDRINFOA,
) -> i32;
type GetaddrinfoFn =
unsafe extern "system" fn(*const u8, *const u8, *const ADDRINFOA, *mut *mut ADDRINFOA) -> i32;
static REAL: OnceLock<GetaddrinfoFn> = OnceLock::new();
static REDIRECT_IP: OnceLock<Vec<u8>> = OnceLock::new();
// NUL-terminated dotted-quad of the resolved OpenFUT server, built once at init
// from the SAME shared config the socket hooks use. getaddrinfo redirects EA
// hostnames here so DNS resolves to the configured server. If configuration was
// missing/invalid this stays empty and EA hostnames are NOT redirected (no
// loopback fallback).
static REDIRECT_HOST: OnceLock<Vec<u8>> = OnceLock::new();
// Flipped to true the first time we successfully apply the runtime cert patch.
// The patch is deferred to here (rather than DllMain) because EAWebKit.dll may
@@ -27,10 +28,12 @@ pub fn set_real(f: GetaddrinfoFn) {
let _ = REAL.set(f);
}
pub fn set_redirect_ip(ip: String) {
let mut bytes = ip.into_bytes();
/// Install the resolved redirect IPv4 (dotted-quad) getaddrinfo will hand back
/// for EA hostnames. Called once at init from the shared resolved server.
pub fn set_redirect_ip(ip: std::net::Ipv4Addr) {
let mut bytes = ip.to_string().into_bytes();
bytes.push(0);
let _ = REDIRECT_IP.set(bytes);
let _ = REDIRECT_HOST.set(bytes);
}
/// Returns true if `host` is an EA / EA-Sports domain that should be redirected
@@ -60,18 +63,30 @@ pub unsafe extern "system" fn hooked_getaddrinfo(
if !CERT_PATCHED.load(Ordering::Relaxed) {
if crate::ssl_patch::patch_eawebkit_cert_verify() {
CERT_PATCHED.store(true, Ordering::Relaxed);
crate::write_log("openfut_hook: ProtoSSL cert-verify patched (lazy, from getaddrinfo)\n");
crate::write_log(
"openfut_hook: ProtoSSL cert-verify patched (lazy, from getaddrinfo)\n",
);
} else {
crate::write_log("openfut_hook: ProtoSSL cert-verify patch FAILED in getaddrinfo\n");
crate::write_log(
"openfut_hook: ProtoSSL cert-verify patch FAILED in getaddrinfo\n",
);
}
}
let redirect = REDIRECT_IP
.get()
.map(|v| v.as_ptr())
.unwrap_or(b"127.0.0.1\0".as_ptr());
let real = REAL.get().copied().unwrap_or(sys_getaddrinfo);
return real(redirect, service_name, hints, result);
// Only redirect when a server was configured & resolved. If not,
// fall through to the real resolver — we never invent a loopback
// destination here.
match REDIRECT_HOST.get() {
Some(redirect) => {
let real = REAL.get().copied().unwrap_or(sys_getaddrinfo);
return real(redirect.as_ptr(), service_name, hints, result);
}
None => {
crate::write_log(
"openfut_hook: EA host seen but no OpenFUT server configured — NOT redirecting\n",
);
}
}
}
}
}