Gap
The eBPF dataplane implements SYN cookie flood protection using kernel kfuncs (bpf_tcp_raw_gen_syncookie_ipv4/v6, bpf_tcp_raw_check_syncookie_ipv4/v6): under SYN flood, XDP generates a SYN-ACK with a cryptographic cookie, replies via XDP_TX, and validates the returning ACK before admitting the connection. The userspace dataplane has no equivalent. Configs with set security flow syn-flood-protection-mode syn-cookie are explicitly rejected by the userspace capability gate, forcing fallback to the eBPF dataplane.
eBPF implementation (source of truth)
bpf/xdp/xdp_screen.c:21-26 — declares kernel kfunc helpers
bpf/xdp/xdp_screen.c:138 — bpf_tcp_raw_gen_syncookie_ipv4(iph, tcph, ...) mints cookie
bpf/xdp/xdp_screen.c:254 — return XDP_TX reflects the SYN-ACK back to the client
bpf/xdp/xdp_screen.c:419 — bpf_tcp_raw_check_syncookie_ipv4(iph, tcph) validates returning ACK
bpf/headers/xpf_common.h:311 — SCREEN_SYN_COOKIE (1 << 14) flag and synproxy_active state in struct flood_state
pkg/dataplane/userspace/snapshot.go:1518-1521 — userspaceSupportsScreenProfiles() returns false when SynFloodProtectionMode == \"syn-cookie\"
Userspace-dp gap
Searched: grep -rn 'syn_cookie\\|SYN_COOKIE\\|syncookie\\|synproxy' userspace-dp/src/ — zero matches.
userspace-dp/src/screen.rs implements synproxy_active=false only — SynProfile::syn_flood_threshold triggers a drop rather than a cookie reply.
Recommended fix
Implement RFC 4987-style SYN cookie keyed-MAC handling in userspace-dp/src/screen.rs:
- Per-zone SipHash/keyed-MAC secret + 64-second rotation
- On SYN-flood detection: mint cookie from
(src_ip, src_port, dst_ip, dst_port, mss_idx, t), build SYN-ACK frame, hand to TX completion pipeline for reply
- On returning ACK from suspect source: validate cookie, on success synthesize the SYN as if it arrived, install session
- Remove
SynFloodProtectionMode == \"syn-cookie\" gate in pkg/dataplane/userspace/snapshot.go:1518
Alternative: punt SYN-flood traffic to kernel tcp_syncookies=2 mode via a TC redirect — operationally simpler but loses XDP-rate processing.
Blocker for #1373
This must land before Phase 4 (BPF source removal) of #1373 (retire eBPF dataplane). Currently the userspace capability gate falls back to the eBPF dataplane when this config is set; once eBPF is removed the fallback target disappears.
Refined contract (added 2026-05-17 after triple-review of #1384)
See docs/pr/1373-retire-ebpf-dataplane/plan-1374-syn-cookies.md for the full implementation contract refined through 4 rounds of Claude+Codex+Gemini Pro 3 review. New since the original issue body:
- Epoch contract: transmit
epoch & 0x1f (5 bits); MAC and secret derivation use the full monotonic epoch. Validation tries current + previous full epochs whose low 5 bits match the transmitted field. A cookie minted 32 epochs ago has matching low bits but must reject because its full epoch is outside the validation window.
- Epoch publication must be generation-atomic with the secret snapshot — workers must not see new full epoch with old per-zone secret or vice versa.
- Risks called out: replay/wrap (32-epoch ambiguity), failover skew (bounded monotonic-epoch skew across HA peers), budget starvation (reply budget must not drain forwarding frames), validated-client cache pressure (no eviction by attacker-generated valid-looking ACKs).
- Required tests added:
screen::syn_cookie_epoch_low_bits_wrap_rejects_32_epoch_old_cookie, screen::syn_cookie_validation_tries_current_and_previous_full_epoch, screen::syn_cookie_budget_drop_does_not_starve_tx, plus deriveUserspaceCapabilities() admit-only-after-wired Go gate.
Gap
The eBPF dataplane implements SYN cookie flood protection using kernel kfuncs (
bpf_tcp_raw_gen_syncookie_ipv4/v6,bpf_tcp_raw_check_syncookie_ipv4/v6): under SYN flood, XDP generates a SYN-ACK with a cryptographic cookie, replies viaXDP_TX, and validates the returning ACK before admitting the connection. The userspace dataplane has no equivalent. Configs withset security flow syn-flood-protection-mode syn-cookieare explicitly rejected by the userspace capability gate, forcing fallback to the eBPF dataplane.eBPF implementation (source of truth)
bpf/xdp/xdp_screen.c:21-26— declares kernel kfunc helpersbpf/xdp/xdp_screen.c:138—bpf_tcp_raw_gen_syncookie_ipv4(iph, tcph, ...)mints cookiebpf/xdp/xdp_screen.c:254—return XDP_TXreflects the SYN-ACK back to the clientbpf/xdp/xdp_screen.c:419—bpf_tcp_raw_check_syncookie_ipv4(iph, tcph)validates returning ACKbpf/headers/xpf_common.h:311—SCREEN_SYN_COOKIE (1 << 14)flag andsynproxy_activestate instruct flood_statepkg/dataplane/userspace/snapshot.go:1518-1521—userspaceSupportsScreenProfiles()returns false whenSynFloodProtectionMode == \"syn-cookie\"Userspace-dp gap
Searched:
grep -rn 'syn_cookie\\|SYN_COOKIE\\|syncookie\\|synproxy' userspace-dp/src/— zero matches.userspace-dp/src/screen.rsimplementssynproxy_active=falseonly —SynProfile::syn_flood_thresholdtriggers a drop rather than a cookie reply.Recommended fix
Implement RFC 4987-style SYN cookie keyed-MAC handling in
userspace-dp/src/screen.rs:(src_ip, src_port, dst_ip, dst_port, mss_idx, t), build SYN-ACK frame, hand to TX completion pipeline for replySynFloodProtectionMode == \"syn-cookie\"gate inpkg/dataplane/userspace/snapshot.go:1518Alternative: punt SYN-flood traffic to kernel
tcp_syncookies=2mode via a TC redirect — operationally simpler but loses XDP-rate processing.Blocker for #1373
This must land before Phase 4 (BPF source removal) of #1373 (retire eBPF dataplane). Currently the userspace capability gate falls back to the eBPF dataplane when this config is set; once eBPF is removed the fallback target disappears.
Refined contract (added 2026-05-17 after triple-review of #1384)
See
docs/pr/1373-retire-ebpf-dataplane/plan-1374-syn-cookies.mdfor the full implementation contract refined through 4 rounds of Claude+Codex+Gemini Pro 3 review. New since the original issue body:epoch & 0x1f(5 bits); MAC and secret derivation use the full monotonic epoch. Validation tries current + previous full epochs whose low 5 bits match the transmitted field. A cookie minted 32 epochs ago has matching low bits but must reject because its full epoch is outside the validation window.screen::syn_cookie_epoch_low_bits_wrap_rejects_32_epoch_old_cookie,screen::syn_cookie_validation_tries_current_and_previous_full_epoch,screen::syn_cookie_budget_drop_does_not_starve_tx, plusderiveUserspaceCapabilities()admit-only-after-wired Go gate.