docs: add FLE bridge direction pivot and squad-injection test tooling
Adds the app-centric FLE bridge direction (direction.md) replacing the Blaze-backend route as primary plan, plus a corrected foundational test procedure and snapshot/diff/apply tooling for reverse-engineering FLE's Freeze Lineup write mechanism. Also picks up prior untracked research docs (status-review, fut-integration-options, fifa23-startup-flow, track-c) and existing capture/export tooling that hadn't been committed yet.
This commit is contained in:
Executable
+135
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env bash
|
||||
# network-metadata-logger/netlog.sh
|
||||
# Logs FIFA 23 network connection metadata: host, port, protocol, timing.
|
||||
# Does NOT capture payload, does NOT decrypt TLS.
|
||||
#
|
||||
# Usage: netlog.sh [--interval 2] [--duration 120]
|
||||
# Polls /proc/net/tcp* and resolves FIFA23 PIDs every N seconds.
|
||||
# Output: CSV to stdout and netlog-TIMESTAMP.csv in this directory.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
INTERVAL="${INTERVAL:-2}"
|
||||
DURATION="${DURATION:-300}"
|
||||
OUT_DIR="$(cd "$(dirname "$0")" && pwd)/logs"
|
||||
mkdir -p "$OUT_DIR"
|
||||
OUT_FILE="$OUT_DIR/netlog-$(date +%Y%m%d-%H%M%S).csv"
|
||||
|
||||
log() { echo "$*" | tee -a "$OUT_FILE"; }
|
||||
|
||||
find_fifa_pids() {
|
||||
pgrep -x FIFA23.exe 2>/dev/null || \
|
||||
pgrep -f FIFA23.exe 2>/dev/null || \
|
||||
true
|
||||
}
|
||||
|
||||
# Decode a hex IP:port pair from /proc/net/tcp
|
||||
# e.g. "0F02000A:01BB" → "10.0.2.15:443"
|
||||
decode_addr() {
|
||||
local hex_ip="${1%%:*}"
|
||||
local hex_port="${1##*:}"
|
||||
local port=$((16#$hex_port))
|
||||
# IPv4 in /proc/net/tcp is little-endian
|
||||
local b1=$((16#${hex_ip:6:2}))
|
||||
local b2=$((16#${hex_ip:4:2}))
|
||||
local b3=$((16#${hex_ip:2:2}))
|
||||
local b4=$((16#${hex_ip:0:2}))
|
||||
echo "${b1}.${b2}.${b3}.${b4}:${port}"
|
||||
}
|
||||
|
||||
# TCP state codes
|
||||
state_name() {
|
||||
case "$1" in
|
||||
01) echo ESTABLISHED ;; 02) echo SYN_SENT ;;
|
||||
03) echo SYN_RECV ;; 04) echo FIN_WAIT1 ;;
|
||||
05) echo FIN_WAIT2 ;; 06) echo TIME_WAIT ;;
|
||||
07) echo CLOSE ;; 08) echo CLOSE_WAIT ;;
|
||||
09) echo LAST_ACK ;; 0A) echo LISTEN ;;
|
||||
0B) echo CLOSING ;; *) echo "STATE_$1" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Resolve remote IP → hostname (best-effort, non-blocking)
|
||||
resolve_host() {
|
||||
local ip="${1%%:*}"
|
||||
# Skip local/loopback
|
||||
case "$ip" in
|
||||
127.*|10.*|192.168.*|172.1[6-9].*|172.2[0-9].*|172.3[0-1].*) echo "$ip"; return ;;
|
||||
esac
|
||||
getent hosts "$ip" 2>/dev/null | awk '{print $2}' | head -1 || echo "$ip"
|
||||
}
|
||||
|
||||
# Categorise destination by port/host heuristic
|
||||
categorise() {
|
||||
local host="$1" port="$2"
|
||||
case "$port" in
|
||||
443|8443) echo "HTTPS/TLS" ;;
|
||||
80) echo "HTTP" ;;
|
||||
10853) echo "EA-LSX-auth" ;;
|
||||
3216|3478|3479|3480) echo "EA-UDP-STUN-or-relay" ;;
|
||||
*)
|
||||
case "$host" in
|
||||
*ea.com*|*easports.com*|*footapi.com*|*ugc.*) echo "EA-service" ;;
|
||||
*akamai*|*amazonaws*|*cloudfront*) echo "CDN" ;;
|
||||
*) echo "other" ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Build inode→pid map from /proc
|
||||
build_inode_pid_map() {
|
||||
declare -gA INODE_PID
|
||||
INODE_PID=()
|
||||
for pid_dir in /proc/[0-9]*/fd; do
|
||||
local pid="${pid_dir%%/fd}"
|
||||
pid="${pid##/proc/}"
|
||||
for link in "$pid_dir"/[0-9]* 2>/dev/null; do
|
||||
local target
|
||||
target=$(readlink "$link" 2>/dev/null) || continue
|
||||
if [[ "$target" == "socket:["* ]]; then
|
||||
local inode="${target//[^0-9]/}"
|
||||
INODE_PID["$inode"]="$pid"
|
||||
fi
|
||||
done
|
||||
done 2>/dev/null || true
|
||||
}
|
||||
|
||||
log "timestamp,pid,proc,local_addr,remote_host,remote_addr,port,state,category"
|
||||
|
||||
declare -A SEEN_CONNS
|
||||
END_TIME=$(( $(date +%s) + DURATION ))
|
||||
|
||||
echo "Logging FIFA 23 network metadata to $OUT_FILE (${DURATION}s, Ctrl-C to stop)..."
|
||||
|
||||
while [ "$(date +%s)" -lt "$END_TIME" ]; do
|
||||
TS=$(date +%H:%M:%S)
|
||||
build_inode_pid_map
|
||||
|
||||
# Read /proc/net/tcp (IPv4 ESTABLISHED and SYN_SENT)
|
||||
while read -r _ local_hex remote_hex state _ _ _ _ _ inode _rest; do
|
||||
[ "$state" = "01" ] || [ "$state" = "02" ] || continue
|
||||
local_addr=$(decode_addr "$local_hex")
|
||||
remote_addr=$(decode_addr "$remote_hex")
|
||||
remote_ip="${remote_addr%%:*}"
|
||||
remote_port="${remote_addr##*:}"
|
||||
pid="${INODE_PID[$inode]:-}"
|
||||
[ -z "$pid" ] && continue
|
||||
|
||||
# Filter to FIFA-related PIDs (or log all if no FIFA found)
|
||||
proc=$(cat "/proc/$pid/comm" 2>/dev/null) || continue
|
||||
|
||||
state_str=$(state_name "$state")
|
||||
key="${pid}:${local_addr}:${remote_addr}"
|
||||
if [ -z "${SEEN_CONNS[$key]:-}" ] || [ "$state_str" != "${SEEN_CONNS[$key]}" ]; then
|
||||
SEEN_CONNS["$key"]="$state_str"
|
||||
host=$(resolve_host "$remote_ip")
|
||||
cat=$(categorise "$host" "$remote_port")
|
||||
log "$TS,$pid,$proc,$local_addr,$host,$remote_addr,$remote_port,$state_str,$cat"
|
||||
fi
|
||||
done < /proc/net/tcp 2>/dev/null || true
|
||||
|
||||
sleep "$INTERVAL"
|
||||
done
|
||||
|
||||
echo "Done. Output: $OUT_FILE"
|
||||
Reference in New Issue
Block a user