eBPF (XDP + TC-BPF + sock_ops) L3/L4 flood defense for self-hosted game servers. On a single machine whose public IP is directly exposed, it passes UDP game packets only from source IPs that have completed the TCP login handshake, and drops or rate-limits the rest. The goal is not survival but preserving the latency and QoS of legitimate players even while a flood is in progress. The scope is L3/L4 defense at the booter/stresser level (L7 application vulnerabilities and upstream link saturation are out of scope).
| Attack | Defense | RTT p99 (µs) | Loss (%) | core-0 CPU (%) |
|---|---|---|---|---|
| c3-spoof | nftables | 9988 ± 71 | 87.4 | 100.0 |
| c3-spoof | iptables-legacy | 6217 ± 66 | 32.3 | 100.0 |
| c3-spoof | lean (native XDP) | 1829 ± 131 | 0.00 | 1.6 |
| c1-spoof | nftables | 6113 ± 182 | 33.1 | 100.0 |
| c1-spoof | lean (native XDP) | 2808 ± 149 | 0.79 | 85.5 |
- Firewall p99 degrades linearly with load (+8 to +16 µs/Kpps, p≪0.001), but lean stays statistically independent of load, with a slope near 0 and R² near 0.
- All 16 metric×attack combinations have ICC=0 (no measurement variance between cycles, which means very high reproducibility).
- Full numbers, regressions, and figures are in
results/analysis-cycles-1-10/(FINDINGS.md,CONNTRACK_BIMODALITY.md).
src/ eBPF dataplane (the product itself): guard.c, maps.h, Makefile
scripts/ operations + measurement scripts (flat layout, lib/common.sh is the node/IP/IF SSOT)
report/ final report PDF (EN) + figures/ (fig1-4, table CSVs)
results/ analysis-cycles-1-10/ (aggregation, regression, figures) + summaries/ (per-cycle CSV)
scripts/ depends on relative-path source and REPO_ROOT computation, so the flat layout must be kept as is.
- Operations (deployment):
attach_lean.sh,detach_all.sh,lean_guard.py(userspace control),setup_victim.sh,lib/common.sh - Measurement (reproduction):
run_sweep.sh,run_final.sh,collect_metrics.sh,verify_results.sh,summarize_results.py,make_result_figures.py, attack generators (attack_pktgen.sh,syn_flood*,pktgen_mt.sh), firewall comparison (ipt_legacy.sh,nft_rules.sh), and so on - Raw run payloads (hundreds of MB per cycle) are not included in this distribution.
Kernel 6.6+ is recommended (TC uses the tcx link), cgroup v2 with CONFIG_CGROUP_BPF (needed for sock_ops), and net.core.bpf_jit_enable=1. Dependencies: clang llvm libbpf-dev linux-headers-$(uname -r) bpftool.
sudo ./scripts/setup_victim.sh # one-time: prepare the environment (governor/core isolation/headers/jit) and build guard.o
make -C src # auto-detects arch (x86_64/aarch64), normal profile (10k maps)
make -C src MAP_PROFILE=high # 100k maps. min|normal|high|max = 1k|10k|100k|1M (fixed at build time)
make -C src verify # (optional) dry load check, does not attachAttach all three hooks (XDP, TC, sock_ops) together. $IF is the victim NIC, check it with ip link.
sudo ./scripts/attach_lean.sh --iface eno1 --xdp-mode native # native|generic|auto
python3 ./scripts/lean_guard.py stats # drop/pass/blacklist/conn_cap counters
python3 ./scripts/lean_guard.py events # ringbuf tail
python3 ./scripts/lean_guard.py dump-all # full snapshot (JSON)
sudo ./scripts/detach_all.sh --iface eno1 # reverse order, idempotentRuntime tuning is limited to the 8 fields of config_map plus manual map entries (changing defense logic means a rebuild, map size is set at build time, mode and iface are set at attach time).
python3 ./scripts/lean_guard.py config set max_conn_per_ip=8 # concurrent-connection cap (0=off)
python3 ./scripts/lean_guard.py config getThe config_map fields are max_tokens (100), refill_rate (50/s), violation_threshold (10), max_conn_per_ip (0), block_duration_s (300), whitelist_ttl_s (300), and login_port/game_port (25565).
--victim label in scripts/lib/common.sh.
sudo ./scripts/run_sweep.sh --victim victim1 --hirate # attack×defense×pps sweep
sudo ./scripts/run_final.sh # repeated (cycle) batch run
./scripts/verify_results.sh # check output consistency
python3 ./scripts/summarize_results.py # headline summary
python3 ./scripts/make_result_figures.py # generate result figures (fig3/fig4 etc.)Outputs land in results/<victim>/<defense>/<pps>/<attack>/run<n>/ (victim ∈ {victim0, victim1, victim-demo}; defense ∈ {none, ipt-legacy, nft, lean}; attack ∈ {c1, c3} × {single, spoof}). The provenance of each run is guaranteed by the commit hash in meta.json.
Because the eBPF dataplane declares SEC("license")="GPL", this repository is distributed under GPL-2.0.
This distribution repository was curated and derived from commit c6e5e5a (2026-06-15) of the development repository pi-guard. The ADRs (decision records), the full design documents (runbook, ARCHITECTURE, and test-plan, which is the measurement SSOT), and the raw measurement data are kept in the development repository.