#!/usr/bin/env bash
# ============================================================================
# OpenFUT FIFA-17 — CLIENT-side arming (runs on the GAME machine, e.g. 105).
#
# Companion to the dev container on the SERVER (120). The server runs the heavy
# responders (Blaze / UTAS / roster / POW). Two pieces are inherently local to
# the game and therefore stay here:
#
#   * autopatch.py  — patches FIFA17.exe process memory (ProtoSSL cert-verify).
#                     Must run where the game runs; cannot be containerised.
#   * lsx_responder — the Origin/EADesktop emulator the game dials on the
#                     hardcoded loopback 127.0.0.1:4216. Loopback IPC can't be
#                     cleanly redirected to a remote host, so it lives here.
#
# Everything the game reaches by a routable address is redirected to the server:
#   * winter15.gosredirector.ea.com (hardcoded EA IP 159.153.51.20) -> SERVER:42127
#   * easw.easports.com (dead hardcoded UTAS host)                  -> SERVER (:8099)
#
# The server's responders were started with OPENFUT_ADVERTISE=<SERVER_IP>, so
# after these first redirected contacts the game is handed <SERVER_IP> for every
# later hop (Blaze main, roster, UTAS, telemetry) and dials the server directly.
#
# Usage:   sudo OPENFUT_SERVER=203.0.113.10 ./client_arm.sh
#   (re-run after every reboot; the sysctl/iptables state is volatile)
# ============================================================================
set -euo pipefail

SERVER="${OPENFUT_SERVER:?set OPENFUT_SERVER to the backend host IP, e.g. 203.0.113.10}"
GOS_EA_IP="159.153.51.20"     # winter15.gosredirector.ea.com (hardcoded in FIFA17)
UTAS_HOST="easw.easports.com" # dead UTAS host baked into CardsDLL
UTAS_RE="${UTAS_HOST//./\\.}" # same, safe to embed in a regex

if [ "$(id -u)" -ne 0 ]; then
  echo "!! must run as root (sudo). Re-run: sudo OPENFUT_SERVER=$SERVER $0" >&2
  exit 1
fi

echo "[client_arm] backend server = $SERVER"

# 1) allow /proc/PID/mem writes (autopatch's ProtoSSL cert-verify patch)
sysctl -q kernel.yama.ptrace_scope=0

# 2) Redirect the hardcoded Blaze redirector IP to the server's redirector.
#    (Replace any stale rule first so re-runs and IP changes are clean.)
while iptables -t nat -D OUTPUT -p tcp -d "$GOS_EA_IP" -j DNAT \
        --to-destination "$SERVER:42127" 2>/dev/null; do :; done
iptables -t nat -A OUTPUT -p tcp -d "$GOS_EA_IP" -j DNAT --to-destination "$SERVER:42127"

# 2b) DNAT from OUTPUT to a REMOTE host needs a matching source-NAT on the way
#     out, or the server's replies (from its own IP) won't match the game's
#     conntrack entry. MASQUERADE the redirected flow so it is SNAT'd to this
#     host's outbound IP. (Harmless duplicate-guarded like the DNAT above.)
while iptables -t nat -D POSTROUTING -p tcp -d "$SERVER" --dport 42127 \
        -j MASQUERADE 2>/dev/null; do :; done
iptables -t nat -A POSTROUTING -p tcp -d "$SERVER" --dport 42127 -j MASQUERADE

# 3) Point the dead hardcoded UTAS host at the server. The port (8099) is carried
#    in the game's own URL, so only the name needs redirecting. Remove any prior
#    OpenFUT-managed line (loopback or other server) and write the current one.
sed -i "/[[:space:]]${UTAS_RE}\b.*# openfut\$/d" /etc/hosts
printf '%s\t%s\t# openfut\n' "$SERVER" "$UTAS_HOST" >> /etc/hosts

echo "[client_arm] --- armed ---"
sysctl kernel.yama.ptrace_scope
iptables -t nat -L OUTPUT -n | grep -i "$GOS_EA_IP" || echo "  (DNAT missing!)"

# Verify the hosts entry by EFFECT, not by presence.
#
# glibc returns the FIRST match in /etc/hosts, so our line can be written
# correctly and still lose to an earlier one -- and the sed above only removes
# lines this script wrote (`# openfut`), so re-running never clears a foreign
# one. The old check here was `grep easw /etc/hosts && echo ok`, which passed on
# the shadowing line itself and reported success while resolution was wrong.
#
# Observed on 2026-08-11: a leftover `127.0.0.1 easw.easports.com` from the
# single-machine era shadowed the OpenFUT line, and every re-run said "ok".
resolved="$(getent ahosts "$UTAS_HOST" 2>/dev/null | awk '{print $1}' | sort -u | tr '\n' ' ')"
# SERVER may be a hostname, so compare address-to-address rather than comparing
# the literal string against resolved IPs (which would warn spuriously).
server_ips="$(getent ahosts "$SERVER" 2>/dev/null | awk '{print $1}' | sort -u)"
[ -n "$server_ips" ] || server_ips="$SERVER"
match=0
for ip in $server_ips; do
  printf '%s' "$resolved" | grep -qw -- "$ip" && match=1
done
if [ "$match" -eq 1 ]; then
  echo "  /etc/hosts ok ($UTAS_HOST -> $resolved)"
else
  echo
  echo "  !! WARNING: $UTAS_HOST resolves to [$resolved], not $SERVER."
  echo "     An earlier /etc/hosts line is shadowing the OpenFUT one:"
  grep -nE "^[[:space:]]*[^#].*[[:space:]]${UTAS_RE}([[:space:]]|\$)" /etc/hosts \
    | grep -v '# openfut$' | sed 's/^/       /' || true
  echo
  echo "     Not fatal: the responders advertise $SERVER, so the game stops using"
  echo "     this name after the first hop. Worth removing the line above anyway."
  echo "     Lines are listed rather than deleted -- this script will not remove"
  echo "     /etc/hosts entries it did not write."
fi
echo
echo "[client_arm] Next: start the LOCAL pieces (LSX + autopatch) with client_local.sh,"
echo "             ensure the container is up on $SERVER, then launch FIFA 17."
