| Tool | TCP Bandwidth | UDP Bandwidth | UDP Loss |
|---|---|---|---|
| gutd (eBPF) (v3.0.7) | 1.52 Gbits/sec | 1.78 Gbits/sec | 0.066% |
| gutd (Userspace) (v3.0.7) | 818 Mbits/sec | 961 Mbits/sec | 32% |
| wg-obfuscator (v1.5) | 394 Mbits/sec | 315 Mbits/sec | 71% |
* Performance measured using iperf3 between 2 isolated network namespaces on GitHub Actions Ubuntu 22.04 runners. See test logic and full logs. Last updated: 2026-04-22 12:29 |
gutd v3 transparently obfuscates WireGuard UDP traffic using a Linux TC/XDP eBPF datapath. On egress the TC BPF program wraps each WireGuard packet in a chosen obfuscation envelope, masks the payload with a ChaCha keystream and optionally pads it. On ingress the XDP program validates, strips the envelope and restores the original packet before WireGuard sees it. WireGuard is completely unaware of gutd. A pure userspace mode (wire-compatible with the eBPF path) is available for older kernels, unprivileged containers, MikroTik RouterOS, and Windows.
| Mode | obfs= |
Wire appearance | Anti-probing | Ports |
|---|---|---|---|---|
| QUIC (default) | quic |
Fake QUIC Long Header + SNI (looks like HTTPS/3) | XDP replies with QUIC Version Negotiation | any UDP |
| GUT | gut |
GOST-like random UDP — no QUIC/TLS signatures | silent drop | any UDP |
| SIP/RTP | sip |
Signaling packets wrapped in SIP headers; data in RTP frames | XDP replies with 200 OK / 401 / 403 |
ports[0] = SIP (5060), ports[1+] = RTP (≥ 2 required) |
| Syslog | syslog |
Payload base64-encoded inside a fake syslog message | silent drop | any UDP (514 typical) |
All modes apply ChaCha payload masking on top of the envelope. Both peers must use the same mode.
- Four obfuscation modes: QUIC, GUT (GOST-like random UDP), SIP/RTP, Syslog — selectable per peer
- Active DPI probe deflection at XDP layer (QUIC: Version Negotiation; SIP:
200 OK/401/403) - WireGuard payload masking with ChaCha (4 rounds by default)
- TC egress hook on a veth pair, XDP ingress hook on the physical NIC
- Port striping: multiple UDP ports per peer with per-packet rotation
- Keepalive probabilistic drop to suppress WireGuard timing fingerprints
- Variable padding to obscure packet sizes
- Hot reload via SIGHUP (BPF map update, no restart)
- Pure userspace fallback mode (zero eBPF requirements, ~500 Mbps capable)
- Cross-platform: Linux (eBPF + userspace), Windows (userspace), RouterOS (userspace)
- Multi-peer support (one veth pair + BPF program per peer)
- Static musl build, zero OS dependencies — runs in empty
scratchcontainers - IPv4 and IPv6 outer transport
- Dynamic peer endpoint learning for clients behind NAT (
peer_ip = dynamic) - Stats via
gutd statusor SIGUSR1 signal
Generate a shared key and create a minimal config on both peers:
gutd genkey # → prints 256-bit hex key# /etc/gutd/gutd.conf (Linux)
# C:\ProgramData\gutd\gutd.conf (Windows)
[peer]
peer_ip = 203.0.113.10 # remote peer public IP
ports = 41000
key = <output of gutd genkey>
# obfs = quic # quic (default) | gut | sip | syslogMTU note: The obfuscation envelope adds overhead on top of the WireGuard packet. Set your WireGuard interface MTU accordingly (see MTU reference below):
Mode Overhead Recommended WG MTU quic16 bytes 1420 (default) gut10 bytes 1420 sip22 bytes (RTP+GUT) 1400 syslogbase64 expansion 800
# eBPF mode (default on Linux, requires root and kernel ≥ 5.17)
sudo ./gutd /etc/gutd/gutd.conf
# Pure userspace mode (Linux — no eBPF, no root with capabilities)
GUTD_USERSPACE=1 ./gutd /etc/gutd/gutd.conf
# Windows (always userspace, run as Administrator for install)
gutd.exe gutd.conf
# Reload config without restart (Linux)
sudo kill -HUP $(pgrep gutd)# Linux (default, with eBPF)
cargo build --release
# Linux static musl binary
./build-musl.sh
# Windows (userspace only, cross-compile from Linux)
cargo build --release --target x86_64-pc-windows-gnu --no-default-featuresSee BUILD.md for cross-compilation and musl details.
Each obfuscation mode adds a different amount of overhead to every WireGuard packet. You must set the WireGuard interface MTU lower than the default 1420 for modes that add more than 16 bytes, otherwise oversized frames will be silently dropped by the network link.
| Mode | Header added by gutd | Max safe WG MTU* |
|---|---|---|
quic |
16 bytes (QUIC short header) | 1420 |
gut |
10 bytes (GUT header) | 1420 |
sip |
22 bytes (RTP 12 + GUT 10) | 1400 |
syslog |
base64 expansion (~4/3×) | 800 |
* For a 1500-byte outer link MTU (standard Ethernet). Adjust proportionally for PPPoE (1492) or other links.
SIP special requirement: sip mode requires at least 2 ports — ports[0] carries
SIP signaling packets and ports[1+] carry RTP data frames. gutd will refuse to start
with fewer than 2 ports in SIP mode.
gutd eBPF programs use bpf_loop (kernel ≥ 5.17) and noinline BPF subprograms.
The BPF verifier complexity budget (processed insns) varies significantly across
kernel versions due to verifier improvements in state pruning and precision tracking.
| Kernel | QUIC | GUT | Syslog | SIP | Notes |
|---|---|---|---|---|---|
| ≥ 6.1 | ✅ | ✅ | ✅ | ✅ | Fully tested; 6.1 uses -mcpu=v3 + verifier-safe clamps |
| 5.17 – 6.0 | ✅ | Only GUT mode is reliable | |||
| < 5.17 | ❌ | ❌ | ❌ | ❌ | No bpf_loop; use userspace mode |
GUTD_USERSPACE=1 as a fallback on older kernels.
# Correct SIP config example
[peer]
obfs = sip
ports = 5060, 10000, 10001 # [0]=signaling [1+]=RTP
mtu = 1400
sni = sip.example.com
key = <shared key>| Document | Description |
|---|---|
| doc/configuration.md | Full config reference, obfs modes, MTU tuning |
| doc/running.md | All running modes: basic, P2P, RouterOS, relay |
| doc/architecture.md | Egress/ingress datapath, userspace daemon, security |
| doc/testing.md | Unit and integration tests |
| doc/troubleshooting.md | Troubleshooting, firewall notes |
| BUILD.md | Build instructions |
| METRICS.md | Stats counters |
Dual-licensed: userspace code under MIT, eBPF/kernel code under GPL-2.0-only. See LICENSE.