Skip to content

MedovTimur/syn-guard

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

syn-guard

A small XDP/eBPF SYN-flood guard for a single destination IPv4 + TCP port.
It counts SYN packets per source IP in a sliding time window and blacklists sources that exceed a threshold.


What it does

  • Attaches an XDP program to an interface (DRV or SKB mode).
  • Filters only traffic matching:
    • destination IPv4 = --addr
    • destination TCP port = --dest-port
  • Detects SYN && !ACK bursts per source IP.
  • When the per-window counter reaches syn_threshold, the source IP is added to BLACKLIST and subsequent packets are dropped immediately.
  • Optionally tracks lightweight counters via a Per-CPU stats map.

🧱 Repository layout

workspace: this repo is a Cargo workspace with three crates and one helper script.

.
β”œβ”€β”€ syn-guard/              # userspace loader / CLI (attaches XDP, writes CONFIG, prints stats)
β”‚   └── src/main.rs
β”œβ”€β”€ syn-guard-ebpf/         # eBPF/XDP program (no_std)
β”‚   β”œβ”€β”€ src/main.rs
β”‚   β”œβ”€β”€ src/packet.rs
β”‚   └── src/stats.rs
β”œβ”€β”€ syn-guard-common/       # shared structs (Config, Counters, SynStats)
β”‚   └── src/lib.rs
└── show_blacklist.py       # helper: dump BLACKLIST map via bpftool

πŸ›  Tech stack & requirements

Language / stack

  • Rust (userspace)
  • Rust no_std eBPF program via Aya (XDP)

Toolchain & system requirements

  • Linux with eBPF/XDP support (VMs are OK; veth works best with SKB mode)
  • ip (iproute2), bpftool, tcpdump
  • For generating traffic: hping3 (or alternatives)
  • Rust toolchain compatible with Aya eBPF builds
  • Sufficient RLIMIT_MEMLOCK (the program sets it to infinity)

Feature flags

  • syn-guard (userspace) features:

    • ebpf-stats β€” builds the eBPF object with stats enabled
  • syn-guard-ebpf (eBPF) features:

    • stats β€” enables the STATS PerCpuArray map and counter increments

How it wires together: syn-guard’s build script checks CARGO_FEATURE_EBPF_STATS and passes stats into the syn-guard-ebpf build.


πŸ— Architecture

High-level flow

  1. Userspace syn-guard loads the compiled eBPF object (syn-guard-ebpf).
  2. It writes runtime configuration into CONFIG[0] (dst IPv4, dst port, window length, threshold).
  3. It attaches the XDP program syn_guard to the interface that has the --addr IPv4.
  4. The XDP program inspects packets:
    • Non-IPv4 / non-TCP / other dst IP/port => PASS
    • Fragmented IP packets => PASS
    • Already in BLACKLIST => DROP
    • SYN && !ACK => update per-src counters in SYN_STATS
    • If threshold reached => insert to BLACKLIST, increment banned, DROP
  5. Optional: userspace periodically reads STATS (per-CPU) and prints deltas.

Components

syn-guard (userspace)

Responsibilities:

  • Discover interface by IPv4 (--addr)
  • Raise memlock rlimit
  • Load eBPF bytecode
  • Initialize Aya logger (optional)
  • Populate CONFIG map
  • Attach/detach XDP program
  • Poll STATS and print deltas

syn-guard-ebpf (XDP program)

Responsibilities:

  • Parse Ethernet/IPv4/TCP headers safely (bounds checks)
  • Apply filtering logic for a single dst IP/port
  • Maintain maps:
    • BLACKLIST: src IP β†’ marker byte
    • SYN_STATS: src IP β†’ sliding-window counters (LRU to limit memory)
    • STATS (optional): global counters

syn-guard-common

Responsibilities:

  • Define #[repr(C)] POD structs shared between user and eBPF:
    • Config, SynStats, Counters

πŸ—ƒ State model / storage layout

Maps (eBPF)

CONFIG: Array<Config> (size 1)

  • Key: u32 index (only 0 is used)
  • Value: Config
  • Purpose: runtime configuration set by userspace once at startup

BLACKLIST: HashMap<[u8; 4], u8>

  • Key: source IPv4 in network-order bytes
  • Value: u8 marker (usually 1)
  • Invariant: if key exists β†’ source is banned; packets are dropped early

SYN_STATS: LruHashMap<[u8; 4], SynStats>

  • Key: source IPv4 in network-order bytes
  • Value: SynStats { window_start_ns, syn_count }
  • Behavior: LRU eviction keeps memory bounded under high-cardinality attacks

STATS: PerCpuArray<Counters> (optional, enabled by stats)

  • Index: 0
  • Value: Counters per CPU
  • Read model: userspace sums per-CPU values and prints deltas

πŸ”Œ CLI / API

syn-guard CLI

syn-guard --addr <IPv4> --dest-port <PORT> [--xdp-mode auto|drv|skb] [--stats-interval SECONDS]

Arguments:

  • --addr <IPv4>: destination IPv4 to protect (also used to find the interface)
  • --dest-port <u16>: destination TCP port to protect
  • --xdp-mode <auto|drv|skb>:
    • auto: try DRV first, fallback to SKB
    • drv: driver/native XDP (fastest, needs NIC support)
    • skb: generic XDP (best for veth/VMs)
  • --stats-interval <u64>: how often to print stats deltas (seconds)

πŸ“ˆ Diagram (sequence)

sequenceDiagram
    autonumber
    participant U as User
    participant S as syn-guard (userspace)
    participant X as XDP prog (syn_guard)
    participant M as BPF maps

    U->>S: start with --addr/--dest-port
    S->>M: write CONFIG[0]
    S->>X: load + attach to iface (XDP)
    loop each packet
      X->>X: parse Eth/IPv4/TCP (bounds checks)
      alt not target dst ip/port or not TCP
        X-->>S: XDP_PASS
      else blacklisted
        X->>M: lookup BLACKLIST[src]
        X-->>S: XDP_DROP
      else SYN && !ACK
        X->>M: update SYN_STATS[src]
        alt threshold reached
          X->>M: insert BLACKLIST[src]
          X-->>S: XDP_DROP
        else
          X-->>S: XDP_PASS
        end
      end
    end
    loop every stats interval
      S->>M: read STATS (per-CPU)
      S-->>U: print deltas
    end
Loading

πŸš€ Quick start

1) Install dependencies (Ubuntu)

sudo apt-get update
sudo apt-get install -y iproute2 bpftool tcpdump hping3 python3

2) Build

Without stats (minimal):

cargo build -p syn-guard --release

With stats enabled:

cargo build -p syn-guard --release --features ebpf-stats

Note: enabling stats is done via userspace feature ebpf-stats, not stats.

3) Create network namespaces (hardcoded nsA/nsB, vethA/vethB)

These commands must be run as root:

# Clean leftovers (safe to run even if they don't exist)
sudo ip netns del nsA 2>/dev/null || true
sudo ip netns del nsB 2>/dev/null || true
sudo ip link del vethA 2>/dev/null || true

# Create namespaces
sudo ip netns add nsA
sudo ip netns add nsB

# Create veth pair
sudo ip link add vethA type veth peer name vethB

# Move interfaces into namespaces
sudo ip link set vethA netns nsA
sudo ip link set vethB netns nsB

# Assign IPs
sudo ip netns exec nsA ip addr add 192.168.100.1/24 dev vethA
sudo ip netns exec nsB ip addr add 192.168.100.2/24 dev vethB

# Bring links up
sudo ip netns exec nsA ip link set dev vethA up
sudo ip netns exec nsB ip link set dev vethB up

4) Observe traffic with tcpdump (nsB)

sudo ip netns exec nsB tcpdump -i vethB -nn -v ip

5) Run syn-guard (nsB)

sudo ip netns exec nsB /home/ubuntu/syn-guard/target/release/syn-guard \
  --addr 192.168.100.2 --dest-port 5555 --xdp-mode skb --stats-interval 1

Expected output (example):

Attached XDP (SKB_MODE) to vethB. Filtering dst 192.168.100.2:5555
stats(+1s): pass=... drop=... syn_seen=... banned=... bl_hits=... parse_err=...

6) Generate SYN flood from nsA

Full flood (very aggressive):

sudo ip netns exec nsA hping3 -S --flood -p 5555 192.168.100.2 -I vethA

Safer bounded burst (recommended for debugging):

sudo ip netns exec nsA hping3 -S -c 260 -i u2000 -p 5555 192.168.100.2 -I vethA

🧾 Inspect BLACKLIST with show_blacklist.py

Print once

sudo python3 show_blacklist.py --netns nsB --once

Example:

[12:45:27] BLACKLIST size=1
192.168.100.1

Watch continuously (polling)

sudo python3 show_blacklist.py --netns nsB --interval 1.0

Show only newly added IPs

sudo python3 show_blacklist.py --netns nsB --diff --interval 1.0

Script flags summary

  • --netns <name>: run bpftool inside a network namespace (ip netns exec)
  • --map <name>: map name to dump (default BLACKLIST)
  • --once: dump once and exit
  • --interval <sec>: polling interval
  • --diff: print only newly added IPs since previous poll

About

No description, website, or topics provided.

Resources

License

Apache-2.0 and 2 other licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
GPL-2.0
LICENSE-GPL2
MIT
LICENSE-MIT

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors