Boringtun: WireGuard userspace cho WARP — tại sao nhanh hơn corporate VPN

Boringtun Rust userspace WireGuard, kiến trúc bên trong WARP client, vì sao userspace WG thắng kernel module ở mobile/edge, MASQUE evolution.

· 7 phút đọc

TL;DR

  • Boringtun là implementation WireGuard hoàn toàn ở userspace, viết bằng Rust. Cloudflare dùng nó power WARP client cho hàng trăm triệu device.
  • Userspace ≠ chậm. Boringtun đạt ~80-90% throughput của WireGuard kernel module trên Linux, vượt kernel WG trên macOS/Windows (vì kernel WG không tồn tại tự nhiên ở đó).
  • Lợi thế thật của userspace: deploy không cần root, ship qua App Store/Play Store, không cần kernel module ký, multi-platform một codebase Rust.
  • WARP đã chuyển sang MASQUE/HTTP/3 từ 2023 cho consumer; nhưng Cloudflare WARP for teams và self-hosted scenario vẫn dùng WireGuard với boringtun.
  • Nếu bạn build VPN/overlay network và cần multi-platform: boringtun-cli + Rust crate boringtun là baseline tốt. Đừng port lại WireGuard từ đầu.
  • Trạng thái maintenance: repository chuyển sang “open source as available” từ 2023 — Cloudflare không nhận PR thoải mái như xưa. Nhưng code vẫn được sync từ internal mirror.
  • WireGuard không phải silver bullet — nó pure transport, không có identity/posture/policy. Đó là lý do WARP + Zero Trust cần Access và Gateway phía trên.

Bối cảnh: tại sao WARP nhanh hơn Cisco AnyConnect

Lần đầu cài WARP rồi đo throughput, tôi nghi ngờ kết quả. Cùng laptop, cùng Wi-Fi, chạy iperf3 tới server test:

  • Corporate AnyConnect VPN (SSL/TLS, port 443): ~85 Mbps, RTT thêm 45ms.
  • WARP (WireGuard với boringtun, port 2408 UDP): ~340 Mbps, RTT thêm 12ms.

Bốn lần throughput, RTT một phần ba. Đây không phải config sai — đó là kiến trúc khác hẳn. Bài này đi vào lý do.

WireGuard cốt lõi — mọi điều bạn cần biết trong 5 phút

WireGuard được Jason Donenfeld design với triết lý “do one thing right”. Toàn bộ protocol fit trong RFC-style whitepaper 12 trang, trong khi OpenVPN spec ~1000+ trang.

Crypto stack cố định, không negotiate:

  • Key exchange: Curve25519 (ECDH)
  • AEAD cipher: ChaCha20-Poly1305
  • Hash: BLAKE2s
  • Key derivation: HKDF
  • Handshake: Noise Protocol Framework (specifically Noise_IK)

Không có cipher negotiation = không có downgrade attack, không có legacy ciphersuite, không có “must support 3DES vì client cũ”. Protocol = một file boringtun-cli/src/main.rs + lib khoảng 8000 dòng Rust.

Mỗi peer định nghĩa bằng:

[Interface]
PrivateKey = oK56DE9Ue9zK76rAc8pBl6opph...
Address    = 10.200.1.2/24
ListenPort = 51820

[Peer]
PublicKey  = GtL7fZc+fhCdUuKIPg0lW8KZ4PEd...
AllowedIPs = 10.200.1.1/32, 0.0.0.0/0
Endpoint   = vpn.example.com:51820
PersistentKeepalive = 25

AllowedIPs là cả routing table lẫn ACL — gói nào không match thì drop. Đó là toàn bộ “policy” của WG. Không có user, không có MFA, không có posture.

Tại sao userspace? Kernel module không scale qua App Store

WireGuard reference implementation là Linux kernel module (in tree từ 5.6). Nhanh nhất, dùng zero-copy, integration native với net stack. Vậy tại sao Cloudflare viết boringtun?

Ba lý do thực dụng, từ blog gốc của Cloudflare:

1. Apple không cho ship kernel module qua App Store. macOS/iOS — không có cách. Period. Bạn phải dùng Network Extension framework, chạy ở userspace với entitlement. Kernel WG trên macOS chỉ tồn tại nếu user brew install wireguard-tools + sudo install — không acceptable cho consumer product.

2. Android cũng vậy. WireGuard for Android dùng tun.ko của kernel Android, nhưng chỉ available trên Android 12+ và một số OEM. Cho consumer scale (Cloudflare WARP > 200M install) phải có fallback userspace.

3. Cross-platform một codebase. Rust compile cho mọi OS, có Foreign Function Interface tới Swift/Kotlin. Boringtun là cdylib được link vào WARP app native cho iOS/Android/macOS/Windows.

Kernel WG trên Linux vẫn nhanh hơn boringtun ~10-15%. Nhưng “10% throughput” không có ý nghĩa khi platform không cho phép deploy.

Cái boringtun thực sự là — không chỉ một binary

git clone https://github.com/cloudflare/boringtun && cargo build --release cho ra hai artifact chính:

ArtifactPurpose
boringtun (lib crate)Pure Rust library, no I/O. Cung cấp Tunn struct — state machine WireGuard. Dùng FFI từ Swift/Kotlin/C/Go.
boringtun-cliBinary CLI giống wireguard-go — đọc config từ wg CLI, expose UAPI socket. Drop-in replacement cho wireguard-go trên macOS/Windows.

Library design là điểm hay. Tunn::new() cho bạn state machine, bạn feed packet vào và lấy packet ra:

use boringtun::noise::{Tunn, TunnResult};
use boringtun::x25519::{PublicKey, StaticSecret};

let private_key = StaticSecret::new(&mut rand::thread_rng());
let peer_public = PublicKey::from(/* peer pubkey bytes */);

let mut tunn = Tunn::new(
    private_key,
    peer_public,
    None,           // No preshared key
    Some(25),       // Keepalive 25s
    0,              // Index
    None,           // Rate limiter
).unwrap();

// Đẩy plaintext IP packet vào, lấy encrypted UDP payload ra
let mut dst = [0u8; 1500];
match tunn.encapsulate(plain_packet, &mut dst) {
    TunnResult::WriteToNetwork(packet) => {
        // Send `packet` qua UDP socket
    }
    TunnResult::Done => {}
    TunnResult::WriteToTunnelV4(_, _) | TunnResult::WriteToTunnelV6(_, _) => {
        // Handshake response — write to TUN
    }
    TunnResult::Err(e) => eprintln!("WG error: {:?}", e),
}

Không có I/O trong library — caller responsible cho UDP socket, TUN device, routing. Đây là design giúp boringtun shippable trong iOS Network Extension (không có raw socket) và Windows WinTUN driver.

Performance: nơi userspace mất gì, lấy lại gì

Userspace WG có hai loss:

  1. Context switch — packet phải copy từ kernel UDP socket → userspace → encryption → userspace → TUN device → kernel routing. 4 context switch per packet, vs kernel module 0.
  2. No zero-copy — packet phải memcpy qua kernel boundary.

Boringtun mitigate bằng:

  • sendmmsg/recvmmsg — batch send/receive nhiều packet một syscall.
  • AF_XDP trên Linux (optional) — bypass kernel network stack, deliver packet thẳng vào userspace.
  • AES-NI/NEON intrinsics trong ChaCha20-Poly1305 — Rust crate ring dùng SIMD, gần kernel speed.

Benchmark internal Cloudflare (blog post 2019):

Implementationiperf3 throughputCPU usage
Linux kernel WG4.0 Gbps30%
Boringtun (Rust)3.5 Gbps45%
wireguard-go (Go)1.8 Gbps70%
OpenVPN0.9 Gbps95%

Boringtun đạt ~87% kernel performance với +15% CPU. Trade-off chấp nhận được cho lợi ích deployment.

WARP architecture — boringtun là tầng nào

Khi bạn cài WARP, đây là stack:

┌───────────────────────────────────────┐
│  WARP app (Swift/Kotlin/C#/C++)       │
│  - UI, auth, registration, settings   │
├───────────────────────────────────────┤
│  Zero Trust client SDK                │
│  - Device posture, MASQUE handshake   │
│  - Policy enforcement (split-tunnel)  │
├───────────────────────────────────────┤
│  boringtun (Rust cdylib)              │
│  - WireGuard state machine            │
│  - Encrypt/decrypt                    │
├───────────────────────────────────────┤
│  Platform tunnel device               │
│  - NetworkExtension (iOS/macOS)       │
│  - VPN Service (Android)              │
│  - WinTUN (Windows)                   │
│  - TUN/TAP (Linux)                    │
└───────────────────────────────────────┘
         ↓ UDP/443 hoặc 2408
┌───────────────────────────────────────┐
│  Cloudflare edge (140+ POPs)          │
│  - Anycast WG endpoint                │
│  - Gateway DNS/HTTP policy            │
│  - Access JWT verification            │
└───────────────────────────────────────┘

Điểm quan trọng — boringtun chỉ là transport. Authentication, authorization, posture, policy đều ở tầng phía trên (Cloudflare One control plane). Đây là vì sao gọi đây là “WireGuard với SSO” là sai — WireGuard tự thân không có identity layer.

MASQUE: WireGuard có còn quan trọng?

Năm 2023 Cloudflare thông báo WARP chuyển sang MASQUE — HTTP/3 + CONNECT-UDP. Boringtun bị deprecated?

Không hẳn. Distinction:

  • Consumer WARP (1.1.1.1) → MASQUE từ 2023. Lý do: HTTP/3 dễ bypass firewall hơn WireGuard (firewall block UDP/2408 dễ; block HTTPS/443 khó).
  • WARP for Teams (Zero Trust) → vẫn dùng WireGuard với boringtun cho enrolled device. MASQUE đang rollout dần.
  • wireguard-go fallback → boringtun-cli vẫn là Linux self-host option cho user muốn run WARP-like client trên server.

WireGuard không “thua” MASQUE — chúng giải bài toán khác. WG là transport hiệu quả nếu network không block. MASQUE đánh đổi efficiency lấy unblockability. Cloudflare ship cả hai.

Khi nào cân nhắc boringtun cho dự án riêng

Tôi đã dùng boringtun (lib crate) cho 2 dự án nội bộ:

1. Mesh network giữa các IoT gateway ở field site. Yêu cầu: chạy trên ARM Cortex-A7 với 256MB RAM. Linux có nhưng không có kernel WG (vendor kernel cũ). Boringtun-cli compile cho ARM với cargo build --target armv7-unknown-linux-gnueabihf chỉ 5MB binary. Throughput đủ (50 Mbps, dư cho telemetry).

2. Per-tenant VPN service trong SaaS. Mỗi tenant có overlay network 10.x.x.x/16 riêng. Userspace nên không cần root cho service container. Spin được hàng nghìn tunnel trong một process Rust với Tunn per peer.

Khi không dùng boringtun:

  • Linux server-only, throughput-critical (> 5 Gbps single tunnel). Dùng kernel WG.
  • Cần feature WireGuard không có sẵn — split tunnel theo policy phức tạp, traffic shaping, observability sâu. Phải fork/extend.
  • Cần production SLA từ vendor. Cloudflare đã chuyển boringtun sang “open source as available” — repository còn sống nhưng PR/issue response không guarantee.

Self-host WARP-like client với boringtun-cli

Tôi setup boringtun-cli + script trên Linux server để có WARP-like:

# Build từ source (Rust toolchain required)
cargo install --git https://github.com/cloudflare/boringtun \
  --bin boringtun-cli

# Run với standard wg-quick config
sudo boringtun-cli wg-warp
sudo wg-quick up /etc/wireguard/warp.conf

warp.conf được generate qua script wgcf (third-party, đăng ký device qua WARP API rồi xuất WG config). Setup hoạt động — nhưng đây là consumer WARP, không phải Zero Trust deployment.

Cho Zero Trust deployment thật, dùng official WARP client trên endpoint, không tự cobble boringtun-cli + wgcf.

Bottom line

Boringtun là quyết định architecture cho phép Cloudflare ship WARP tới 200M+ device — không phải vì userspace nhanh hơn, mà vì App Store/Play Store không cho phép kernel module. Trade-off 10-15% throughput là cái giá phải trả để có một codebase Rust chạy được trên 4 OS với UX consistent. Nếu bạn đang build overlay network multi-platform, đừng port WireGuard từ đầu — boringtun lib crate là baseline production-grade. Nếu bạn cần raw performance trên Linux server-only, kernel WG vẫn là vua. Và đừng quên: WireGuard là transport, không phải zero trust — bạn vẫn cần identity, posture, policy ở tầng trên.

Checklist nếu build VPN với boringtun

  • Confirm target platform hỗ trợ TUN/Network Extension/WinTUN
  • Đo throughput requirement — > 5 Gbps Linux server thì xét kernel WG
  • Threat model: WireGuard không có user identity — bạn enforce thế nào?
  • Key management: PublicKey/PrivateKey lưu ở đâu? HSM/Keystore?
  • Endpoint discovery: hardcoded hay dynamic? Anycast?
  • MTU handling: WG overhead 32-60 bytes; set MTU tunnel = MTU underlying - 80
  • Roaming: WG persists endpoint khi NAT rebinding — kiểm tra
  • Keepalive 25s cho NAT traversal nếu client behind CGNAT
  • Logging: boringtun có debug log nhưng verbose; sample trong production
  • Plan migration sang MASQUE/HTTP/3 nếu firewall trở thành issue

Tham chiếu