use std::{ffi::CStr, sync::OnceLock}; use windows_sys::Win32::Networking::WinSock::{ADDRINFOA, getaddrinfo as sys_getaddrinfo}; const INTERCEPT: &[&str] = &[ "fut.ea.com", "utas.mob.v4.fut.ea.com", "utas.s2.fut.ea.com", ]; type GetaddrinfoFn = unsafe extern "system" fn( *const u8, *const u8, *const ADDRINFOA, *mut *mut ADDRINFOA, ) -> i32; static REAL: OnceLock = OnceLock::new(); // Stored as a NUL-terminated byte string so the hook can pass it to getaddrinfo. static REDIRECT_IP: OnceLock> = OnceLock::new(); pub fn set_real(f: GetaddrinfoFn) { let _ = REAL.set(f); } pub fn set_redirect_ip(ip: String) { let mut bytes = ip.into_bytes(); bytes.push(0); // NUL-terminate for passing to getaddrinfo let _ = REDIRECT_IP.set(bytes); } pub unsafe extern "system" fn hooked_getaddrinfo( node_name: *const u8, service_name: *const u8, hints: *const ADDRINFOA, result: *mut *mut ADDRINFOA, ) -> i32 { if !node_name.is_null() { if let Ok(host) = CStr::from_ptr(node_name as *const i8).to_str() { for target in INTERCEPT { if host.eq_ignore_ascii_case(target) { 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); } } } } let real = REAL.get().copied().unwrap_or(sys_getaddrinfo); real(node_name, service_name, hints, result) }