Skip to content

Feature gap: SYN cookie flood protection implemented in eBPF, missing from userspace-dp #1374

@psaab

Description

@psaab

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:138bpf_tcp_raw_gen_syncookie_ipv4(iph, tcph, ...) mints cookie
  • bpf/xdp/xdp_screen.c:254return XDP_TX reflects the SYN-ACK back to the client
  • bpf/xdp/xdp_screen.c:419bpf_tcp_raw_check_syncookie_ipv4(iph, tcph) validates returning ACK
  • bpf/headers/xpf_common.h:311SCREEN_SYN_COOKIE (1 << 14) flag and synproxy_active state in struct flood_state
  • pkg/dataplane/userspace/snapshot.go:1518-1521userspaceSupportsScreenProfiles() 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:

  1. Per-zone SipHash/keyed-MAC secret + 64-second rotation
  2. 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
  3. On returning ACK from suspect source: validate cookie, on success synthesize the SYN as if it arrived, install session
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions